/*
 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 {
  Attention,
  Button,
  convertUiField,
  FormMetadata,
  getConverterById,
  LocalNotificationBanner,
  RenderAllFieldsByUiConfig,
  UIHandlerId,
  useExchangeApiContext,
  useLocalNotificationHandler,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import {
  FormErrors,
  getRequiredFields,
  getShapeFromFields,
  useFormState,
  validateRequiredFields,
} from "../hooks/form.js";
import { undefinedIfEmpty } from "./Start.js";
import {
  AbsoluteTime,
  AccessToken,
  AmountJson,
  Amounts,
  AmountString,
  assertUnreachable,
  createNewOfficerAccount,
  createNewWalletKycAccount,
  HttpStatusCode,
} from "@gnu-taler/taler-util";
import { useEffect, useMemo, useState } from "preact/hooks";

type FormType = {
  amount: AmountJson;
};
type Props = {
  onKycStarted: (token: AccessToken) => void;
};
export function TriggerKyc({ onKycStarted }: Props): VNode {
  const { i18n } = useTranslationContext();
  const [notification, withErrorHandler, notify] =
    useLocalNotificationHandler();
  const { config, lib } = useExchangeApiContext();
  const [kycAccount, setKycAccount] = useState<string>();

  const theForm: FormMetadata = {
    id: "asd",
    version: 1,
    label: i18n.str`Trigger KYC balance`,
    config: {
      type: "double-column",
      design: [
        {
          title: i18n.str`Trigger KYC Balance`,
          fields: [
            {
              id: ".amount" as UIHandlerId,
              type: "amount",
              currency: config.currency,
              label: i18n.str`Amount`,
              required: true,
              converterId: "Taler.Amount",
            },
          ],
        },
      ],
    },
  };

  const shape: Array<UIHandlerId> = [];
  const requiredFields: Array<UIHandlerId> = [];

  theForm.config.design.forEach((section) => {
    Array.prototype.push.apply(shape, getShapeFromFields(section.fields));
    Array.prototype.push.apply(
      requiredFields,
      getRequiredFields(section.fields),
    );
  });
  const [form, state] = useFormState<FormType>(
    shape,
    {
      amount: Amounts.parseOrThrow(`${config.currency}:1000000`),
    },
    (st) => {
      const partialErrors = undefinedIfEmpty<FormErrors<FormType>>({});

      const errors = undefinedIfEmpty<FormErrors<FormType> | undefined>(
        validateRequiredFields(partialErrors, st, requiredFields),
      );

      if (errors === undefined) {
        return {
          status: "ok",
          result: st as any,
          errors: undefined,
        };
      }

      return {
        status: "fail",
        result: st as any,
        errors,
      };
    },
  );

  const accountPromise = useMemo(async () => {
    const resp = await lib.exchange.getSeed();
    const extraEntropy = resp.type === "ok" ? resp.body : new Uint8Array();
    return createNewWalletKycAccount(extraEntropy);
  }, [1]);

  useEffect(() => {
    if (!kycAccount) return;
    const paytoHash = kycAccount
    async function check() {
      const {signingKey} = await accountPromise;
      const result = await lib.exchange.checkKycStatus(signingKey, paytoHash);
      if (result.type === "ok") {
        if (result.body) {
          onKycStarted(result.body.access_token)
        } else {
          console.log("empty body")
        }
      } else {
        switch(result.case) {
          case HttpStatusCode.Forbidden:{
            notify({
              type: "error",
              title: i18n.str`could not create token`,
              description: i18n.str`access denied`,
              when: AbsoluteTime.now(),
            })
          }
          case HttpStatusCode.NotFound: {
            notify({
              type: "error",
              title: i18n.str`could not create token`,
              description: i18n.str`not found`,
              when: AbsoluteTime.now(),
            })
          }
          case HttpStatusCode.Conflict: {
            notify({
              type: "error",
              title: i18n.str`could not create token`,
              description: i18n.str`conflict`,
              when: AbsoluteTime.now(),
            })

          }
        }
      }
    }
    check()
  }, [kycAccount]);

  const submitHandler =
    theForm === undefined || state.status === "fail"
      ? undefined
      : withErrorHandler(
          async () => {
            const account = await accountPromise;

            return lib.exchange.notifyKycBalanceLimit(
              account,
              Amounts.stringify(state.result.amount),
            );
          },
          (res) => {
            notify({
              type: "info",
              title: i18n.str`No kyc required`,
              when: AbsoluteTime.now(),
            });
          },
          (fail) => {
            switch (fail.case) {
              case HttpStatusCode.Forbidden:
                return i18n.str`Access denied trying to test balance.`;
              case HttpStatusCode.UnavailableForLegalReasons:
                setKycAccount(fail.body.h_payto);
                return i18n.str`Unavailable For Legal Reasons`;
              default:
                assertUnreachable(fail);
            }
          },
        );

  if (kycAccount) {
    return <div>loading...</div>
  }

  return (
    <div class="rounded-lg bg-white px-5 py-6 shadow m-4">
      <LocalNotificationBanner notification={notification} />
      <div class="space-y-10 divide-y -mt-5 divide-gray-900/10">
        {theForm.config.design.map((section, i) => {
          if (!section) return <Fragment />;
          return (
            <div
              key={i}
              class="grid grid-cols-1 gap-x-8 gap-y-8 pt-5 md:grid-cols-3"
            >
              <div class="px-4 sm:px-0">
                <h2 class="text-base font-semibold leading-7 text-gray-900">
                  {section.title}
                </h2>
                {section.description && (
                  <p class="mt-1 text-sm leading-6 text-gray-600">
                    {section.description}
                  </p>
                )}
              </div>
              <div class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-md md:col-span-2">
                <div class="p-3">
                  <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
                    <RenderAllFieldsByUiConfig
                      key={i}
                      fields={convertUiField(
                        i18n,
                        section.fields,
                        form,
                        getConverterById,
                      )}
                    />
                  </div>
                </div>
              </div>
            </div>
          );
        })}
      </div>

      <div class="mt-6 flex items-center justify-end gap-x-6">
        <button
          onClick={() => {}}
          class="text-sm font-semibold leading-6 text-gray-900"
        >
          <i18n.Translate>Cancel</i18n.Translate>
        </button>
        <Button
          type="submit"
          handler={submitHandler}
          // disabled={!submitHandler}
          class="disabled:opacity-50 disabled:cursor-default 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>Confirm</i18n.Translate>
        </Button>
      </div>
    </div>
  );
}
