/*
 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 {
  AbsoluteTime,
  AccountLetter,
  HttpStatusCode,
  TalerCorebankApi,
  TalerError,
  TalerErrorCode,
  TranslatedString,
  assertUnreachable,
  parsePaytoUri,
} from "@gnu-taler/taler-util";
import {
  CopyButton,
  Loading,
  LocalNotificationBanner,
  RouteDefinition,
  notifyInfo,
  useBankCoreApiContext,
  useLocalNotification,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
import { useAccountDetails } from "../../hooks/account.js";
import { useBankState } from "../../hooks/bank-state.js";
import { useSessionState } from "../../hooks/session.js";
import { LoginForm } from "../LoginForm.js";
import { ProfileNavigation } from "../ProfileNavigation.js";
import { AccountForm } from "../admin/AccountForm.js";
import { usePreferences } from "../../hooks/preferences.js";

export function ShowAccountDetails({
  account,
  routeClose,
  onUpdateSuccess,
  onAuthorizationRequired,
  routeMyAccountCashout,
  routeMyAccountDelete,
  routeMyAccountDetails,
  routeHere,
  routeMyAccountPassword,
  routeConversionConfig,
}: {
  routeClose: RouteDefinition;
  routeHere: RouteDefinition<{ account: string }>;
  routeMyAccountDetails: RouteDefinition;
  routeMyAccountDelete: RouteDefinition;
  routeMyAccountPassword: RouteDefinition;
  routeMyAccountCashout: RouteDefinition;
  routeConversionConfig: RouteDefinition;
  onUpdateSuccess: () => void;
  onAuthorizationRequired: () => 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, notify, handleError] = useLocalNotification();
  const [, updateBankState] = useBankState();

  const result = useAccountDetails(account);
  if (!result) {
    return <Loading />;
  }
  if (result instanceof TalerError) {
    return (
      <Fragment>
        <ErrorLoadingWithDebug 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);
    }
  }

  async function doUpdate() {
    if (!submitAccount || !creds) return;
    await handleError(async () => {
      const resp = await bank.updateAccount(
        {
          token: creds.token,
          username: account,
        },
        submitAccount,
      );

      if (resp.type === "ok") {
        notifyInfo(i18n.str`Account updated`);
        onUpdateSuccess();
      } else {
        switch (resp.case) {
          case HttpStatusCode.Unauthorized:
            return notify({
              type: "error",
              title: i18n.str`The rights to change the account are not sufficient`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
              when: AbsoluteTime.now(),
            });
          case HttpStatusCode.NotFound:
            return notify({
              type: "error",
              title: i18n.str`The username was not found`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
              when: AbsoluteTime.now(),
            });
          case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME:
            return notify({
              type: "error",
              title: i18n.str`You can't change the legal name, please contact the your account administrator.`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
              when: AbsoluteTime.now(),
            });
          case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
            return notify({
              type: "error",
              title: i18n.str`You can't change the debt limit, please contact the your account administrator.`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
              when: AbsoluteTime.now(),
            });
          case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT:
            return notify({
              type: "error",
              title: i18n.str`You can't change the cashout address, please contact the your account administrator.`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
              when: AbsoluteTime.now(),
            });
          case TalerErrorCode.BANK_MISSING_TAN_INFO:
            return notify({
              type: "error",
              title: i18n.str`No information for the selected authentication channel.`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
              when: AbsoluteTime.now(),
            });
          case HttpStatusCode.Accepted: {
            updateBankState("currentChallenge", {
              operation: "update-account",
              id: String(resp.body.challenge_id),
              location: routeHere.url({ account }),
              sent: AbsoluteTime.never(),
              request: submitAccount,
            });
            return onAuthorizationRequired();
          }
          case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: {
            return notify({
              type: "error",
              title: i18n.str`Authentication channel is not supported.`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
              when: AbsoluteTime.now(),
            });
          }
          case TalerErrorCode.BANK_NON_ADMIN_SET_MIN_CASHOUT: {
            return notify({
              type: "error",
              title: i18n.str`Only the administrator can change the minimum cashout limit.`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
              when: AbsoluteTime.now(),
            });
          }
          default:
            assertUnreachable(resp);
        }
      }
    });
  }

  const url = bank.getRevenueAPI(account);
  const baseURL = url.href;
  const revenueURL = new URL(baseURL);
  revenueURL.username = account;
  revenueURL.password;
  const ac = parsePaytoUri(result.body.payto_uri);
  const payto = !ac?.isKnown ? undefined : ac;
  const accountLetter: AccountLetter | undefined = !payto
    ? undefined
    : {
        accountURI: result.body.payto_uri,
        infoURL: revenueURL.href,
        accountToken: creds?.token,
      };

  return (
    <Fragment>
      <LocalNotificationBanner notification={notification} showDebug={true} />
      {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>
      )}

      <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>
            <button
              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={doUpdate}
            >
              <i18n.Translate>Update</i18n.Translate>
            </button>
          </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>
                      );
                    }
                  }
                })(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>

              {!preferences.showCopyAccount ? (
                <span />
              ) : (
                <CopyButton
                  getContent={() =>
                    !accountLetter ? "" : JSON.stringify(accountLetter)
                  }
                  class="flex text-center 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"
                >
                  <i18n.Translate>Copy</i18n.Translate>
                </CopyButton>
              )}
            </div>
          </div>
        )}
      </div>
    </Fragment>
  );
}
