/*
 This file is part of GNU Taler
 (C) 2021-2024 Taler Systems S.A.

 GNU Taler is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.

 GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */

/**
 *
 * @author Sebastian Javier Marchano (sebasjm)
 */

import {
  AmountString,
  PaytoString,
  TalerMerchantApi,
} from "@gnu-taler/taler-util";
import * as tests from "@gnu-taler/web-util/testing";
import { expect } from "chai";
import { ApiMockEnvironment } from "./testing.js";
import { API_INFORM_TRANSFERS, API_LIST_TRANSFERS } from "./urls.js";
import { useMerchantApiContext } from "@gnu-taler/web-util/browser";
import { useInstanceConfirmedTransfers } from "./transfer.js";

describe("transfer api interaction with listing", () => {
  it("should evict cache when informing a transfer", async () => {
    const env = new ApiMockEnvironment();

    env.addRequestExpectation(API_LIST_TRANSFERS, {
      qparam: { limit: -20 },
      response: {
        transfers: [{ wtid: "2" } as TalerMerchantApi.TransferDetails],
      },
    });

    const moveCursor = (d: string | undefined) => {
      console.log("new position", d);
    };

    const hookBehavior = await tests.hookBehaveLikeThis(
      () => {
        const query = useInstanceConfirmedTransfers({}, moveCursor);
        const { lib: api } = useMerchantApiContext();
        return { query, api };
      },
      {},
      [
        ({ query, api }) => {
          // expect(query.loading).true;
        },

        ({ query, api }) => {
          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
            result: "ok",
          });
          // expect(query.loading).undefined;
          // expect(query.ok).true;
          // if (!query.ok) return;
          // expect(query.data).deep.equals({
          //   transfers: [{ wtid: "2" }],
          // });

          env.addRequestExpectation(API_INFORM_TRANSFERS, {
            request: {
              wtid: "3",
              credit_amount: "EUR:1",
              exchange_url: "exchange.url",
              payto_uri: "payto://",
            },
            response: { total: "" } as any,
          });

          env.addRequestExpectation(API_LIST_TRANSFERS, {
            qparam: { limit: -20 },
            response: {
              transfers: [{ wtid: "3" } as any, { wtid: "2" } as any],
            },
          });

          // api.instance.informWireTransfer(undefined, {
          //   wtid: "3",
          //   credit_amount: "EUR:1" as AmountString,
          //   exchange_url: "exchange.url",
          //   payto_uri: "payto://" as PaytoString,
          // });
        },
        ({ query, api }) => {
          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
            result: "ok",
          });
          // expect(query.loading).undefined;
          // expect(query.ok).true;
          // if (!query.ok) return;

          // expect(query.data).deep.equals({
          //   transfers: [{ wtid: "3" }, { wtid: "2" }],
          // });
        },
      ],
      env.buildTestingContext(),
    );

    expect(hookBehavior).deep.eq({ result: "ok" });
    expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
  });
});

describe("transfer listing pagination", () => {
  it("should not load more if has reach the end", async () => {
    const env = new ApiMockEnvironment();

    env.addRequestExpectation(API_LIST_TRANSFERS, {
      qparam: { limit: -20, payto_uri: "payto://" },
      response: {
        transfers: [{ wtid: "2" }, { wtid: "1" } as any],
      },
    });

    const moveCursor = (d: string | undefined) => {
      console.log("new position", d);
    };
    const hookBehavior = await tests.hookBehaveLikeThis(
      () => {
        const query = useInstanceConfirmedTransfers(
          { payto_uri: "payto://" },
          moveCursor,
        );
        return { query };
      },
      {},
      [
        (query) => {
          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
            result: "ok",
          });
          // expect(query.loading).true;
        },
        (query) => {
          // expect(query.loading).undefined;
          // expect(query.ok).true;
          // if (!query.ok) return;
          // expect(query.data).deep.equals({
          //   transfers: [{ wtid: "2" }, { wtid: "1" }],
          // });
          // expect(query.isReachingEnd).true;
          // expect(query.isReachingStart).true;

        },
      ],
      env.buildTestingContext(),
    );

    expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
    expect(hookBehavior).deep.eq({ result: "ok" });
  });

  it("should load more if result brings more that PAGINATED_LIST_REQUEST", async () => {
    const env = new ApiMockEnvironment();

    const transfersFrom0to20 = Array.from({ length: 20 }).map((e, i) => ({
      wtid: String(i),
    }));
    const transfersFrom20to40 = Array.from({ length: 20 }).map((e, i) => ({
      wtid: String(i + 20),
    }));
    // const transfersFrom20to0 = [...transfersFrom0to20].reverse();

    env.addRequestExpectation(API_LIST_TRANSFERS, {
      qparam: { limit: 20, payto_uri: "payto://", offset: "1" },
      response: {
        transfers: transfersFrom0to20,
      },
    });

    env.addRequestExpectation(API_LIST_TRANSFERS, {
      qparam: { limit: -20, payto_uri: "payto://", offset: "1" },
      response: {
        transfers: transfersFrom20to40,
      },
    });

    const moveCursor = (d: string | undefined) => {
      console.log("new position", d);
    };

    const hookBehavior = await tests.hookBehaveLikeThis(
      () => {
        const query = useInstanceConfirmedTransfers(
          { payto_uri: "payto://", position: "1" },
          moveCursor,
        );
        return { query };
      },
      {},
      [
        (result) => {
          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
            result: "ok",
          });
          // expect(result.loading).true;
        },
        (result) => {
          // expect(result.loading).undefined;
          // expect(result.ok).true;
          // if (!result.ok) return;
          // expect(result.data).deep.equals({
          //   transfers: [...transfersFrom20to0, ...transfersFrom20to40],
          // });
          // expect(result.isReachingEnd).false;
          // expect(result.isReachingStart).false;

          //query more
          env.addRequestExpectation(API_LIST_TRANSFERS, {
            qparam: { limit: -40, payto_uri: "payto://", offset: "1" },
            response: {
              transfers: [...transfersFrom20to40, { wtid: "41" }],
            },
          });
          // result.loadMore();
        },
        (result) => {
          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
            result: "ok",
          });
          // expect(result.loading).true;
        },
        (result) => {
          expect(env.assertJustExpectedRequestWereMade()).deep.eq({
            result: "ok",
          });
          // expect(result.loading).undefined;
          // expect(result.ok).true;
          // if (!result.ok) return;
          // expect(result.data).deep.equals({
          //   transfers: [
          //     ...transfersFrom20to0,
          //     ...transfersFrom20to40,
          //     { wtid: "41" },
          //   ],
          // });
          // expect(result.isReachingEnd).true;
          // expect(result.isReachingStart).false;
        },
      ],
      env.buildTestingContext(),
    );

    expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
    expect(hookBehavior).deep.eq({ result: "ok" });
  });
});
