/*
 This file is part of GNU Taler
 (C) 2020 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/>
 */

/**
 * Imports.
 */
import {
  j2s,
  succeedOrThrow,
  TalerCoreBankHttpClient,
  TransactionMajorState,
  TransactionMinorState,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import {
  createSimpleTestkudosEnvironmentV3,
  registerHarnessBankTestUser,
} from "../harness/environments.js";
import { GlobalTestState, harnessHttpLib } from "../harness/harness.js";

/**
 * Test a cash-acceptor-style withdrawal where the amount
 * is not known upfront but also can't be chosen by the wallet.
 */
export async function runWithdrawalCashacceptorTest(t: GlobalTestState) {
  // Set up test environment

  const { walletClient, exchange, bank } =
    await createSimpleTestkudosEnvironmentV3(t, undefined, {
      forceLibeufin: true,
    });

  const bankClientNg = new TalerCoreBankHttpClient(
    bank.corebankApiBaseUrl,
    harnessHttpLib,
  );

  const bankUser = await registerHarnessBankTestUser(bankClientNg);

  const withdrawalRes = succeedOrThrow(
    await bankClientNg.createWithdrawal(bankUser, {
      no_amount_to_wallet: true,
    }),
  );

  const wop = withdrawalRes;

  const talerWithdrawUri = `${wop.taler_withdraw_uri}?external-confirmation=1`;

  const r1 = await walletClient.call(
    WalletApiOperation.GetWithdrawalDetailsForUri,
    {
      talerWithdrawUri,
    },
  );

  console.log(j2s(r1));

  t.assertTrue(!r1.amount);

  // Withdraw

  const acceptResp = await walletClient.call(
    WalletApiOperation.AcceptBankIntegratedWithdrawal,
    {
      exchangeBaseUrl: exchange.baseUrl,
      talerWithdrawUri,
    },
  );

  // We need to wait until the wallet has registered the reserve information
  // with the bank, as the bank will refuse to confirm before that.
  await walletClient.call(WalletApiOperation.TestingWaitTransactionState, {
    transactionId: acceptResp.transactionId,
    txState: {
      major: TransactionMajorState.Pending,
      minor: TransactionMinorState.BankConfirmTransfer,
    },
  });

  const txns = await walletClient.call(
    WalletApiOperation.GetTransactionsV2,
    {},
  );
  console.log(`transactions: ${j2s(txns)}`);

  succeedOrThrow(
    await bankClientNg.confirmWithdrawalById(
      bankUser,
      {
        amount: "TESTKUDOS:10",
      },
      wop.withdrawal_id,
    ),
  );
  await walletClient.call(WalletApiOperation.TestingWaitTransactionsFinal, {});

  const bal = await walletClient.call(WalletApiOperation.GetBalances, {});

  t.assertAmountEquals(bal.balances[0].available, "TESTKUDOS:9.72");

  // It's a withdrawal from an external account, so it must not
  // show up in the list of bank accounts known to the wallet.
  const bankAccounts = await walletClient.call(
    WalletApiOperation.ListBankAccounts,
    {},
  );
  console.log(`bank accounts: ${j2s(bankAccounts)}`);
  t.assertDeepEqual(bankAccounts.accounts.length, 0);
}

runWithdrawalCashacceptorTest.suites = ["wallet"];
