/*
 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,
  HttpStatusCode,
  TalerCorebankApi,
  TalerError,
  TalerErrorCode,
  TranslatedString,
  assertUnreachable,
} from "@gnu-taler/taler-util";
import {
  Loading,
  LocalNotificationBanner,
  notifyInfo,
  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 { useBankCoreApiContext } from "../../context/config.js";
import { useAccountDetails } from "../../hooks/account.js";
import { useSessionState } from "../../hooks/session.js";
import { useBankState } from "../../hooks/bank-state.js";
import { RouteDefinition } from "../../route.js";
import { LoginForm } from "../LoginForm.js";
import { ProfileNavigation } from "../ProfileNavigation.js";
import { AccountForm } from "../admin/AccountForm.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 { state: credentials } = useSessionState();
  const creds = credentials.status !== "loggedIn" ? undefined : credentials;
  const { bank: api } = 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 <ErrorLoadingWithDebug error={result} />;
  }
  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 api.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,
            });
          case HttpStatusCode.NotFound:
            return notify({
              type: "error",
              title: i18n.str`The username was not found`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
            });
          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,
            });
          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,
            });
          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,
            });
          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,
            });
          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,
            });
          }
          default:
            assertUnreachable(resp);
        }
      }
    });
  }

  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-10 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>
    </Fragment>
  );
}
