/*
 This file is part of GNU Taler
 (C) 2021 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,
  alternativeOrThrow,
  failOrThrow,
  HttpStatusCode,
  LoginTokenScope,
  MerchantAuthMethod,
  succeedOrThrow,
  TalerMerchantInstanceHttpClient,
  TalerMerchantManagementHttpClient,
  TanChannel,
  URL,
} from "@gnu-taler/taler-util";
import {
  ExchangeService,
  getTestHarnessPaytoForLabel,
  GlobalTestState,
  harnessHttpLib,
  MerchantService,
  setupDb,
} from "../harness/harness.js";
import { createTopsEnvironment } from "harness/tops.js";
import { createSimpleTestkudosEnvironmentV3 } from "harness/environments.js";
import { randomBytes } from "node:crypto";
import { chmodSync, writeFileSync } from "node:fs";
import { startTanHelper } from "harness/tan-helper.js";
import { solveMFA } from "./test-merchant-self-provision-inactive-account-permissions.js";

/**
 * The merchant should get the TAN code on request to be used to activate the account.
 */
export async function runMerchantSelfProvisionForgotPasswordTest(
  t: GlobalTestState,
) {
  // Set up test environment

  // FIXME: maybe merchant can use commands?
  const RND = randomBytes(10).toString("hex");
  const socketFile = `${t.testDir}/tan-helper-${RND}.socket`;
  const helperScript = `${t.testDir}/harness-helper-${RND}.sh`;
  writeFileSync(
    helperScript,
    `#!/bin/bash
taler-harness run-helper --socket ${socketFile} -- $@
`,
  );
  chmodSync(helperScript, "777");

  const {
    walletClient,
    bankClient,
    exchange,
    merchant,
    merchantAdminAccessToken,
    bank,
  } = await createSimpleTestkudosEnvironmentV3(t, undefined, {
    additionalMerchantConfig(m) {
      m.modifyConfig(async (cfg) => {
        cfg.setString("merchant", "ENABLE_SELF_PROVISIONING", "yes");
        cfg.setString("merchant", "HELPER_EMAIL", helperScript);
        cfg.setString("merchant", "MANDATORY_TAN_CHANNELS", "email");
      });
    },
  });
  const helper = await startTanHelper({ socketFile });

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

  {
    const r = succeedOrThrow(
      await merchantClient.listInstances(merchantAdminAccessToken),
    );
    t.assertDeepEqual(r.instances.length, 2);
  }

  const instanceInfo = {
    id: "self-instance",
    name: "My instance",
    auth: {
      method: MerchantAuthMethod.TOKEN,
      password: "123",
    },
    default_pay_delay: { d_us: "forever" as const },
    default_wire_transfer_delay: { d_us: "forever" as const },
    jurisdiction: {},
    address: {},
    email: "some@taler.net",
    use_stefan: false,
  };

  const tryCreation = alternativeOrThrow(
    await merchantClient.createInstanceSelfProvision(instanceInfo),
    HttpStatusCode.Accepted,
  );

  await solveMFA(merchantClient, helper, tryCreation, {
    [TanChannel.EMAIL]: instanceInfo.email,
  });

  succeedOrThrow(
    await merchantClient.createInstanceSelfProvision(instanceInfo, {
      challengeIds: tryCreation.challenges.map((c) => c.challenge_id),
    }),
  );

  const instanceApi = new TalerMerchantInstanceHttpClient(
    merchantClient.getSubInstanceAPI(instanceInfo.id),
    merchantClient.httpLib,
  );

  const newPassword = {
    method: MerchantAuthMethod.TOKEN,
    password: "xxx",
  };

  const mfa = alternativeOrThrow(
    await instanceApi.forgotPasswordSelfProvision(newPassword),
    HttpStatusCode.Accepted,
  );

  await solveMFA(instanceApi, helper, mfa, {
    [TanChannel.EMAIL]: instanceInfo.email,
  });

  succeedOrThrow(
    await instanceApi.forgotPasswordSelfProvision(newPassword, {
      challengeIds: mfa.challenges.map((c) => c.challenge_id),
    }),
  );

  const mfa2 = alternativeOrThrow(
    await instanceApi.createAccessToken(instanceInfo.id, newPassword.password, {
      scope: LoginTokenScope.All,
    }),
    HttpStatusCode.Accepted,
  );

  await solveMFA(instanceApi, helper, mfa2, {
    [TanChannel.EMAIL]: instanceInfo.email,
  });

  const tk = succeedOrThrow(
    await instanceApi.createAccessToken(
      instanceInfo.id,
      newPassword.password,
      {
        scope: LoginTokenScope.All,
      },
      {
        challengeIds: mfa2.challenges.map((c) => c.challenge_id),
      },
    ),
  );

  helper.stop();
}

runMerchantSelfProvisionForgotPasswordTest.suites = [
  "merchant",
  "self-provision",
];
