/*
 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 {
  ConfirmPayResultType,
  DonauHttpClient,
  HttpStatusCode,
  j2s,
  OrderOutputType,
  OrderVersion,
  PreparePayResultType,
  succeedOrThrow,
  TalerErrorCode,
  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 { GlobalTestState } from "../harness/harness.js";

/**
 * Test that sets up DONAU but pays without enabling
 * DONAU on the client side.
 */
export async function runDonauCompatTest(t: GlobalTestState) {
  // Set up test environment

  const {
    walletClient,
    bankClient,
    exchange,
    merchant,
    merchantAdminAccessToken,
    commonDb,
  } = await createSimpleTestkudosEnvironmentV3(t);

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

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

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

  await donau.start();

  const donauClient = new DonauHttpClient(donau.baseUrl);

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

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

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

  {
    // Check what happens if we try to add a donau service
    // where the charity_id does not exist.
    const postDonauResp = await merchantClient.postDonau({
      body: {
        charity_id: 42,
        donau_url: donau.baseUrl,
      },
      token: merchantAdminAccessToken,
    });
    t.assertDeepEqual(postDonauResp.case, HttpStatusCode.BadGateway);
    t.assertDeepEqual(
      postDonauResp.detail?.code,
      TalerErrorCode.DONAU_CHARITY_NOT_FOUND,
    );
    console.log(j2s(postDonauResp));
  }

  const orderResp = succeedOrThrow(
    await merchantClient.createOrder(merchantAdminAccessToken, {
      order: {
        version: OrderVersion.V1,
        summary: "Test Donation",
        choices: [
          {
            amount: "TESTKUDOS:10",
            outputs: [
              {
                type: OrderOutputType.TaxReceipt,
                amount: "TESTKUDOS:5",
                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");

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

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

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

  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");
}

runDonauCompatTest.suites = ["donau"];
