/*
 This file is part of GNU Taler
 (C) 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 {
  j2s,
  Logger,
  succeedOrThrow,
  TalerExchangeHttpClient,
  TalerMerchantInstanceHttpClient,
  TalerProtocolTimestamp,
} from "@gnu-taler/taler-util";
import { startFakeChallenger } from "../harness/fake-challenger.js";
import { GlobalTestState, harnessHttpLib } from "../harness/harness.js";
import {
  createTopsEnvironment,
  doFakeChallenger,
  doTopsAcceptTos,
  doTopsKycAuth,
} from "../harness/tops.js";

export const logger = new Logger("test-tops-aml.ts");

export async function runTopsAmlKyxNaturalTest(t: GlobalTestState) {
  // Set up test environment
  const {
    exchange,
    officerAcc,
    merchant,
    exchangeBankAccount,
    merchantAdminAccessToken,
    wireGatewayApi,
    bank,
  } = await createTopsEnvironment(t);

  const challenger = await startFakeChallenger({
    port: 6001,
    addressType: "postal-ch",
  });

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

  // Do KYC auth transfer
  const { accessToken, merchantPaytoHash } = await doTopsKycAuth(t, {
    merchantClient,
    exchangeBankAccount,
    merchantAdminAccessToken,
    wireGatewayApi,
    bank,
  });

  const exchangeClient = new TalerExchangeHttpClient(exchange.baseUrl, {
    httpClient: harnessHttpLib,
  });

  // Accept ToS
  await doTopsAcceptTos(t, {
    accessToken,
    exchangeClient,
    merchantAdminAccessToken,
    merchantClient,
    merchant,
  });

  // Trigger kyx measure.
  {
    const decisionsResp = succeedOrThrow(
      await exchangeClient.getAmlDecisions(officerAcc, {
        active: true,
      }),
    );
    console.log(j2s(decisionsResp));

    t.assertDeepEqual(decisionsResp.records.length, 1);
    const rec = decisionsResp.records[0];

    t.assertDeepEqual(merchantPaytoHash, rec.h_payto);

    succeedOrThrow(
      await exchangeClient.makeAmlDesicion(officerAcc, {
        decision_time: TalerProtocolTimestamp.now(),
        h_payto: rec.h_payto,
        justification: "bla",
        properties: rec.properties ?? {},
        keep_investigating: rec.to_investigate,
        new_measures: "kyx",
        new_rules: {
          custom_measures: {},
          expiration_time: TalerProtocolTimestamp.never(),
          rules: rec.limits.rules,
        },
      }),
    );
  }

  // Upload form.
  {
    const kycInfoResp = await exchangeClient.checkKycInfo(
      accessToken,
      undefined,
      undefined,
    );
    console.log(`kyc info after kyx measure`, j2s(kycInfoResp));
    t.assertDeepEqual(kycInfoResp.case, "ok");
    const kycInfo = kycInfoResp.body;
    t.assertDeepEqual(kycInfo.requirements[0].form, "vqf_902_1_customer");
    t.assertTrue(typeof kycInfo.requirements[0].id === "string");
    const requirementId = kycInfo.requirements[0].id;

    succeedOrThrow(
      await exchangeClient.uploadKycForm(requirementId, {
        FORM_ID: "vqf_902_1_customer",
        FORM_VERSION: 1,
        CUSTOMER_TYPE: "NATURAL_PERSON",
        CUSTOMER_TYPE_VQF: "NATURAL_PERSON",
        FULL_NAME: "Alice A",
        DOMICILE_ADDRESS: "Castle St. 1\nWondertown",
        DATE_OF_BIRTH: "2000-01-01",
        PERSONAL_IDENTIFICATION_DOCUMENT_COPY: "...",
        CUSTOMER_IS_SOLE_PROPRIETOR: false,
        NATIONALITY: "DE",
      }),
    );
  }

  {
    const kycInfoResp = await exchangeClient.checkKycInfo(
      accessToken,
      undefined,
      undefined,
    );
    t.assertDeepEqual(kycInfoResp.case, "ok");
    const requirementId = kycInfoResp.body.requirements[0].id;
    t.assertTrue(typeof requirementId === "string");
    console.log(`kyc info after form upload`, j2s(kycInfoResp));

    const startResp = succeedOrThrow(
      await exchangeClient.startExternalKycProcess(requirementId, {}),
    );
    console.log(`start resp`, j2s(startResp));

    await doFakeChallenger(t, {
      exchangeClient,
      requirementId,
      challenger,
      address: {
        CONTACT_NAME: "Richard Stallman",
        ADDRESS_LINES: "Bundesgasse 1\n1234 Bern",
      },
    });
  }

  {
    const kycInfo = succeedOrThrow(
      await exchangeClient.checkKycInfo(accessToken, undefined, undefined),
    );
    console.log(`kyc info after postal challenger`, j2s(kycInfo));
    t.assertDeepEqual(kycInfo.requirements[0].form, "INFO");
  }

  // We're "done" here, as the AML officer now will just check documents
  // and make a decision.
}

runTopsAmlKyxNaturalTest.suites = ["wallet"];
