/*
 This file is part of GNU Taler
 (C) 2020-2025 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 {
  AccessToken,
  ConfirmPayResultType,
  DonauHttpClient,
  j2s,
  MerchantContractOutputType,
  MerchantContractVersion,
  OrderOutputType,
  OrderVersion,
  PreparePayResultType,
  succeedOrThrow,
  TalerMerchantInstanceHttpClient,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { defaultCoinConfig } from "../harness/denomStructures.js";
import {
  createSimpleTestkudosEnvironmentV3,
  withdrawViaBankV3,
} from "../harness/environments.js";
import { DonauService } from "../harness/harness-donau.js";
import { delayMs, GlobalTestState } from "../harness/harness.js";

export async function runDonauMinusTTest(t: GlobalTestState) {
  // Set up test environment

  const {
    walletClient,
    bankClient,
    exchange,
    merchant,
    merchantAdminAccessToken,
    commonDb,
  } = await createSimpleTestkudosEnvironmentV3(t, undefined, {
    walletConfig: {
      features: {
        enableV1Contracts: true,
      },
    },
  });

  const wres = await withdrawViaBankV3(t, {
    walletClient,
    bankClient,
    amount: "TESTKUDOS:20",
    exchange,
  });
  await wres.withdrawalFinishedCond;

  const donau = DonauService.create(t, {
    currency: "TESTKUDOS",
    database: commonDb.connStr,
    httpPort: 8084,
    name: "donau",
    domain: "Bern",
  });

  donau.addCoinConfigList(defaultCoinConfig.map((x) => x("TESTKUDOS")));

  await donau.start();

  const merchantClient = new TalerMerchantInstanceHttpClient(
    merchant.makeInstanceBaseUrl(),
  );

  const inst = succeedOrThrow(
    await merchantClient.getCurrentInstanceDetails(merchantAdminAccessToken),
  );
  const merchantPub = inst.merchant_pub;

  const donauClient = new DonauHttpClient(donau.baseUrl);

  const currentYear = new Date().getFullYear();

  const charityResp = succeedOrThrow(
    await donauClient.createCharity("" as AccessToken, {
      charity_pub: merchantPub,
      current_year: currentYear,
      max_per_year: "TESTKUDOS:1000",
      charity_name: "42",
      receipts_to_date: "TESTKUDOS:0",
      charity_url: merchant.makeInstanceBaseUrl(),
    }),
  );

  const config = await donauClient.getConfig();
  console.log(`config: ${j2s(config)}`);

  const keys = await donauClient.getKeys();
  console.log(`keys: ${j2s(keys)}`);

  const charityId = charityResp["charity_id"];

  succeedOrThrow(
    await merchantClient.postDonau({
      body: {
        charity_id: charityId,
        donau_url: donau.baseUrl,
      },
      token: merchantAdminAccessToken,
    }),
  );

  await merchant.runDonaukeyupdateOnce();

  const orderResp = succeedOrThrow(
    await merchantClient.createOrder(merchantAdminAccessToken, {
      order: {
        version: OrderVersion.V1,
        summary: "Test Donation",
        choices: [
          {
            amount: "TESTKUDOS:9",
            outputs: [
              {
                type: OrderOutputType.TaxReceipt,
                amount: "TESTKUDOS:9",
                donau_urls: [donau.baseUrl],
              },
            ],
          },
        ],
      },
    }),
  );

  console.log(`order resp: ${j2s(orderResp)}`);

  let orderStatus = succeedOrThrow(
    await merchantClient.getOrderDetails(
      merchantAdminAccessToken,
      orderResp.order_id,
    ),
  );

  t.assertTrue(orderStatus.order_status === "unpaid");

  await walletClient.call(WalletApiOperation.SetDonau, {
    donauBaseUrl: donau.baseUrl,
    taxPayerId: "test-tax-payer",
  });

  const preparePayResult = await walletClient.call(
    WalletApiOperation.PreparePayForUri,
    {
      talerPayUri: orderStatus.taler_pay_uri,
    },
  );

  console.log(`preparePayResult: ${j2s(preparePayResult)}`);

  t.assertTrue(
    preparePayResult.status === PreparePayResultType.ChoiceSelection,
  );

  t.assertDeepEqual(
    preparePayResult.contractTerms.version,
    MerchantContractVersion.V1,
  );
  const outTok = preparePayResult.contractTerms.choices[0].outputs[0];
  t.assertDeepEqual(outTok.type, MerchantContractOutputType.TaxReceipt);

  t.assertDeepEqual(outTok.donau_urls, [donau.baseUrl]);

  // t.assertTrue(!!outTok.amount);

  // t.assertAmountEquals(outTok.amount, "TESTKUDOS:5");

  const r2 = await walletClient.call(WalletApiOperation.ConfirmPay, {
    transactionId: preparePayResult.transactionId,
    choiceIndex: 0,
    useDonau: true,
  });

  t.assertDeepEqual(r2.type, ConfirmPayResultType.Done);

  // Check if payment was successful.

  orderStatus = succeedOrThrow(
    await merchantClient.getOrderDetails(
      merchantAdminAccessToken,
      orderResp.order_id,
    ),
  );

  t.assertDeepEqual(orderStatus.order_status, "paid");
}

runDonauMinusTTest.suites = ["donau"];
runDonauMinusTTest.experimental = true
