/*
 This file is part of GNU Taler
 (C) 2022-2024 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/>
 */
import {
  HttpStatusCode,
  TalerCorebankApi,
  TalerError,
  TalerErrorCode,
  assertUnreachable
} from "@gnu-taler/taler-util";
import {
  Attention,
  ButtonBetter,
  CopyButton,
  ErrorLoading,
  Loading,
  LocalNotificationBanner,
  RouteDefinition,
  makeSafeCall,
  notifyInfo,
  useBankCoreApiContext,
  useChallengeHandler,
  useLocalNotificationBetter,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";

import { Paytos } from "@gnu-taler/taler-util";
import { useAccountDetails } from "../../hooks/account.js";
import { usePreferences } from "../../hooks/preferences.js";
import { LoggedIn, useSessionState } from "../../hooks/session.js";
import { AccountForm } from "../admin/AccountForm.js";
import { LoginForm } from "../LoginForm.js";
import { ProfileNavigation } from "../ProfileNavigation.js";
import { SolveMFAChallenges } from "../SolveMFA.js";

const TALER_SCREEN_ID = 118;

export function ShowAccountDetails({
  account,
  routeClose,
  onUpdateSuccess,

  routeMyAccountCashout,
  routeMyAccountDelete,
  routeMyAccountDetails,
  routeMyAccountPassword,
  routeConversionConfig,
}: {
  routeClose: RouteDefinition;
  routeMyAccountDetails: RouteDefinition;
  routeMyAccountDelete: RouteDefinition;
  routeMyAccountPassword: RouteDefinition;
  routeMyAccountCashout: RouteDefinition;
  routeConversionConfig: RouteDefinition;
  onUpdateSuccess: () => void;

  account: string;
}): VNode {
  const { i18n } = useTranslationContext();
  const [preferences] = usePreferences();
  const { state: credentials } = useSessionState();
  const creds = credentials.status !== "loggedIn" ? undefined : credentials;
  const {
    lib: { bank },
  } = useBankCoreApiContext();
  const accountIsTheCurrentUser =
    credentials.status === "loggedIn"
      ? credentials.username === account
      : false;

  const [submitAccount, setSubmitAccount] = useState<
    TalerCorebankApi.AccountReconfiguration | undefined
  >();
  const [notification, notifyOnError] = useLocalNotificationBetter();
  const mfa = useChallengeHandler();

  const result = useAccountDetails(account);
  if (!result) {
    return <Loading />;
  }
  if (result instanceof TalerError) {
    return (
      <Fragment>
        <ErrorLoading error={result} />
        <LoginForm currentUser={account} />
      </Fragment>
    );
  }
  if (result.type === "fail") {
    switch (result.case) {
      case HttpStatusCode.Unauthorized:
      case HttpStatusCode.NotFound:
        return <LoginForm currentUser={account} />;
      default:
        assertUnreachable(result);
    }
  }

  const [doUpdate, repeatUpdate] = mfa.withMfaHandler(
    ({ challengeIds, onChallengeRequired }) =>
      makeSafeCall(
        i18n,
        (creds: LoggedIn, account: TalerCorebankApi.AccountReconfiguration) =>
          bank.updateAccount(creds, account, { challengeIds }),
        (success) => {
          notifyInfo(i18n.str`Account updated`);
          onUpdateSuccess();
        },
        (fail) => {
          switch (fail.case) {
            case HttpStatusCode.Unauthorized:
              return i18n.str`The rights to change the account are not sufficient`;
            case HttpStatusCode.NotFound:
              return i18n.str`The username was not found`;
            case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME:
              return i18n.str`You can't change the legal name, please contact the your account administrator.`;
            case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
              return i18n.str`You can't change the debt limit, please contact the your account administrator.`;
            case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT:
              return i18n.str`You can't change the cashout address, please contact the your account administrator.`;
            case TalerErrorCode.BANK_MISSING_TAN_INFO:
              return i18n.str`No information for the selected authentication channel.`;
            case HttpStatusCode.Accepted: {
              onChallengeRequired(fail.body);
              return i18n.str`A second factor authentication is required.`;
            }
            case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
              return i18n.str`Authentication channel is not supported.`;
            case TalerErrorCode.BANK_NON_ADMIN_SET_CONVERSION_RATE_CLASS:
              return i18n.str`Only the administrator can change the conversion rate.`;
            case TalerErrorCode.BANK_CONVERSION_RATE_CLASS_UNKNOWN:
              return i18n.str`The conversion rate class doesn't exist.`;
            case TalerErrorCode.BANK_PASSWORD_TOO_SHORT:
              return i18n.str`The password is too short. Can't have less than 8 characters.`;
            case TalerErrorCode.BANK_PASSWORD_TOO_LONG:
              return i18n.str`The password is too long. Can't have more than 64 characters.`;
          }
        },
      ),
  );

  const updateHandler =
    !creds || !submitAccount
      ? undefined
      : () => notifyOnError(doUpdate)(creds, submitAccount);

  const url = bank.getRevenueAPI(account);
  const baseURL = url.href;
  const revenueURL = new URL(baseURL);
  revenueURL.username = account;
  revenueURL.password;
  const ac = Paytos.fromString(result.body.payto_uri);
  const payto = ac.type === "fail" || !ac.body.targetType ? undefined : ac.body;

  if (mfa.pendingChallenge && repeatUpdate) {
    return (
      <SolveMFAChallenges
        currentChallenge={mfa.pendingChallenge}
        description={i18n.str`Update account information.`}
        onCancel={mfa.doCancelChallenge}
        username={account}
        onCompleted={repeatUpdate}
      />
    );
  }

  return (
    <Fragment>
      <LocalNotificationBanner notification={notification} />
      {accountIsTheCurrentUser ? (
        <ProfileNavigation
          current="details"
          routeMyAccountCashout={routeMyAccountCashout}
          routeMyAccountDelete={routeMyAccountDelete}
          routeConversionConfig={routeConversionConfig}
          routeMyAccountDetails={routeMyAccountDetails}
          routeMyAccountPassword={routeMyAccountPassword}
        />
      ) : (
        <h1 class="text-base font-semibold leading-6 text-gray-900">
          <i18n.Translate>Account "{account}"</i18n.Translate>
        </h1>
      )}

      {result.body.status !== "deleted" ? undefined : (
        <Attention title={i18n.str`Removed`} type="info">
          <i18n.Translate>This account can't be used.</i18n.Translate>
        </Attention>
      )}

      <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
        <div class="px-4 sm:px-0">
          <h2 class="text-base font-semibold leading-7 text-gray-900">
            <div class="flex items-center justify-between">
              <span class="flex flex-grow flex-col">
                <span
                  class="text-sm text-black font-semibold leading-6 "
                  id="availability-label"
                >
                  <i18n.Translate>Change details</i18n.Translate>
                </span>
              </span>
            </div>
          </h2>
        </div>

        <AccountForm
          focus={true}
          username={account}
          template={result.body}
          purpose="update"
          onChange={(a) => setSubmitAccount(a)}
        >
          <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
            <a
              href={routeClose.url({})}
              name="cancel"
              class="text-sm font-semibold leading-6 text-gray-900"
            >
              <i18n.Translate>Cancel</i18n.Translate>
            </a>
            <ButtonBetter
              type="submit"
              name="update"
              class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
              disabled={!submitAccount}
              onClick={updateHandler}
            >
              <i18n.Translate>Update</i18n.Translate>
            </ButtonBetter>
          </div>
        </AccountForm>
      </div>
      <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-6 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
        <div class="px-4 sm:px-0">
          <h2 class="text-base font-semibold leading-7 text-gray-900">
            <div class="flex items-center justify-between">
              <span class="flex flex-grow flex-col">
                <span
                  class="text-sm text-black font-semibold leading-6 "
                  id="availability-label"
                >
                  <i18n.Translate>Merchant integration</i18n.Translate>
                </span>
              </span>
            </div>
          </h2>
          <p class="mt-2 text-sm text-gray-500">
            <i18n.Translate>
              Use this information to link your Taler Merchant Backoffice
              account with the current bank account. You can start by copying
              the values, then go to your merchant backoffice service provider,
              login into your account and look for the "import" button in the
              "bank account" section.
            </i18n.Translate>
          </p>
        </div>

        {payto !== undefined && (
          <div class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2">
            <div class="px-4 py-6 sm:p-8">
              <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
                <div class="sm:col-span-5">
                  <label
                    class="block text-sm font-medium leading-6 text-gray-900"
                    for="account-type"
                  >
                    {i18n.str`Account type`}
                  </label>
                  <div class="mt-2">
                    <input
                      type="text"
                      class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                      name="account-type"
                      id="account-type"
                      disabled={true}
                      value={payto.targetType}
                      autocomplete="off"
                    />
                  </div>
                  <p class="mt-2 text-sm text-gray-500">
                    <i18n.Translate>
                      Method to use for wire transfer.
                    </i18n.Translate>
                  </p>
                </div>
                {((payto) => {
                  switch (payto.targetType) {
                    case "iban": {
                      return (
                        <div class="sm:col-span-5">
                          <label
                            class="block text-sm font-medium leading-6 text-gray-900"
                            for="iban"
                          >
                            {i18n.str`IBAN`}
                          </label>
                          <div class="mt-2">
                            <div class="flex justify-between">
                              <input
                                type="text"
                                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                                name="iban"
                                id="iban"
                                disabled={true}
                                value={payto.iban}
                                autocomplete="off"
                              />
                              <CopyButton
                                class="p-2 rounded-full  text-black shadow-sm  focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
                                getContent={() => payto.iban}
                              />
                            </div>
                          </div>
                          <p class="mt-2 text-sm text-gray-500">
                            <i18n.Translate>
                              International Bank Account Number.
                            </i18n.Translate>
                          </p>
                        </div>
                      );
                    }
                    case "x-taler-bank": {
                      return (
                        <Fragment>
                          <div class="sm:col-span-5">
                            <label
                              class="block text-sm font-medium leading-6 text-gray-900"
                              for="account-host"
                            >
                              {i18n.str`Account name`}
                            </label>
                            <div class="mt-2">
                              <div class="flex justify-between">
                                <input
                                  type="text"
                                  class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                                  name="account-host"
                                  id="account-host"
                                  disabled={true}
                                  value={payto.host}
                                  autocomplete="off"
                                />
                              </div>
                              <CopyButton
                                class="p-2 rounded-full  text-black shadow-sm  focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
                                getContent={() => payto.host}
                              />
                            </div>

                            <p class="mt-2 text-sm text-gray-500">
                              <i18n.Translate>
                                Bank host where the service is located.
                              </i18n.Translate>
                            </p>
                          </div>
                          <div class="sm:col-span-5">
                            <label
                              class="block text-sm font-medium leading-6 text-gray-900"
                              for="account-name"
                            >
                              {i18n.str`Account name`}
                            </label>
                            <div class="mt-2">
                              <div class="flex justify-between">
                                <input
                                  type="text"
                                  class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                                  name="account-name"
                                  id="account-name"
                                  disabled={true}
                                  value={payto.account}
                                  autocomplete="off"
                                />
                              </div>
                              <CopyButton
                                class="p-2 rounded-full  text-black shadow-sm  focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
                                getContent={() => payto.account}
                              />
                            </div>

                            <p class="mt-2 text-sm text-gray-500">
                              <i18n.Translate>
                                Bank account identifier for wire transfers.
                              </i18n.Translate>
                            </p>
                          </div>
                        </Fragment>
                      );
                    }
                    case "bitcoin": {
                      return (
                        <div class="sm:col-span-5">
                          <label
                            class="block text-sm font-medium leading-6 text-gray-900"
                            for="iban"
                          >
                            {i18n.str`Address`}
                          </label>
                          <div class="mt-2">
                            <input
                              type="text"
                              class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                              name="iban"
                              id="iban"
                              disabled={true}
                              value={"asd"}
                              autocomplete="off"
                            />
                            <CopyButton
                              class="p-2 rounded-full  text-black shadow-sm  focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
                              getContent={() => "Asd"}
                            />
                          </div>
                          <p class="mt-2 text-sm text-gray-500">
                            <i18n.Translate>
                              International Bank Account Number.
                            </i18n.Translate>
                          </p>
                        </div>
                      );
                    }
                    default:
                      return `unsupported account type ${payto.targetType}`;
                  }
                })(payto)}

                <div class="sm:col-span-5">
                  <label
                    class="block text-sm font-medium leading-6 text-gray-900"
                    for="iban"
                  >
                    {i18n.str`Owner's name`}
                  </label>
                  <div class="mt-2">
                    <div class="flex justify-between">
                      <input
                        type="text"
                        class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                        name="iban"
                        id="iban"
                        disabled={true}
                        value={result.body.name}
                        autocomplete="off"
                      />
                      <CopyButton
                        class="p-2 rounded-full  text-black shadow-sm  focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
                        getContent={() => result.body.name}
                      />
                    </div>
                  </div>
                  <p class="mt-2 text-sm text-gray-500">
                    <i18n.Translate>
                      Legal name of the person holding the account.
                    </i18n.Translate>
                  </p>
                </div>
                <div class="sm:col-span-5">
                  <label
                    class="block text-sm font-medium leading-6 text-gray-900"
                    for="iban"
                  >
                    {i18n.str`Account info URL`}
                  </label>
                  <div class="mt-2">
                    <div class="flex justify-between">
                      <input
                        type="text"
                        class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                        name="iban"
                        id="iban"
                        disabled={true}
                        value={baseURL}
                        autocomplete="off"
                      />
                      <CopyButton
                        class="p-2 rounded-full  text-black shadow-sm  focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
                        getContent={() => baseURL}
                      />
                    </div>
                  </div>
                  <p class="mt-2 text-sm text-gray-500">
                    <i18n.Translate>
                      From where the merchant can download information about
                      incoming wire transfers to this account.
                    </i18n.Translate>
                  </p>
                </div>
              </div>
            </div>
            <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
              <a
                href={routeClose.url({})}
                name="cancel"
                class="text-sm font-semibold leading-6 text-gray-900"
              >
                <i18n.Translate>Cancel</i18n.Translate>
              </a>
              <span></span>
            </div>
          </div>
        )}
      </div>
    </Fragment>
  );
}
