/*
 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 {
  Button,
  InputLine,
  InternationalizationAPI,
  LocalNotificationBanner,
  UIHandlerId,
  useLocalNotificationHandler,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import {
  FormErrors,
  FormStatus,
  FormValues,
  RecursivePartial,
  useFormState,
} from "../hooks/form.js";
import { useOfficer } from "../hooks/officer.js";
import { usePreferences } from "../hooks/preferences.js";

type FormType = {
  password: string;
  repeat: string;
};
function createFormValidator(
  i18n: InternationalizationAPI,
  allowInsecurePassword: boolean,
) {
  return function check(
    state: RecursivePartial<FormValues<FormType>>,
  ): FormStatus<FormType> {
    const errors = undefinedIfEmpty<FormErrors<FormType>>({
      password: !state.password
        ? i18n.str`required`
        : allowInsecurePassword
          ? undefined
          : state.password.length < 8
            ? i18n.str`should have at least 8 characters`
            : !state.password.match(/[a-z]/) && state.password.match(/[A-Z]/)
              ? i18n.str`should have lowercase and uppercase characters`
              : !state.password.match(/\d/)
                ? i18n.str`should have numbers`
                : !state.password.match(/[^a-zA-Z\d]/)
                  ? i18n.str`should have at least one character which is not a number or letter`
                  : undefined,

      repeat: !state.repeat
        ? i18n.str`required`
        : state.password !== state.repeat
          ? i18n.str`doesn't match`
          : undefined,
    });

    if (errors === undefined) {
      const result: FormType = {
        password: state.password!,
        repeat: state.repeat!,
      };
      return {
        status: "ok",
        result,
        errors,
      };
    }
    const result: RecursivePartial<FormType> = {
      password: state.password,
      repeat: state.repeat,
    };
    return {
      status: "fail",
      result,
      errors,
    };
  };
}

export function undefinedIfEmpty<T extends object | undefined>(obj: T): T | undefined {
  if (obj === undefined) return undefined;
  return Object.keys(obj).some(
    (k) => (obj as Record<string, T>)[k] !== undefined,
  )
    ? obj
    : undefined;
}

export function CreateAccount(): VNode {
  const { i18n } = useTranslationContext();
  const [settings] = usePreferences();
  const officer = useOfficer();

  const [notification, withErrorHandler] = useLocalNotificationHandler();

  const [form, status] = useFormState<FormType>(
    [".password", ".repeat"] as Array<UIHandlerId>,
    {
      password: undefined,
      repeat: undefined,
    },
    createFormValidator(i18n, settings.allowInsecurePassword),
  );

  const createAccountHandler =
    status.status === "fail" || officer.state !== "not-found"
      ? undefined
      : withErrorHandler(
          async () => officer.create(form.password!.value!),
          () => {},
        );
  return (
    <div class="flex min-h-full flex-col ">
      <LocalNotificationBanner notification={notification} />

      <div class="sm:mx-auto sm:w-full sm:max-w-md">
        <h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
          <i18n.Translate>Create account</i18n.Translate>
        </h2>
      </div>

      <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px] ">
        <div class="bg-gray-100 px-6 py-6 shadow sm:rounded-lg sm:px-12">
          <form
            class="space-y-6"
            noValidate
            onSubmit={(e) => {
              e.preventDefault();
            }}
            autoCapitalize="none"
            autoCorrect="off"
          >
            <div class="mt-2">
              <InputLine<FormType, "password">
                label={i18n.str`Password`}
                name="password"
                type="password"
                required
                handler={form.password}
              />
            </div>

            <div class="mt-2">
              <InputLine<FormType, "repeat">
                label={i18n.str`Repeat password`}
                name="repeat"
                type="password"
                required
                handler={form.repeat}
              />
            </div>

            <div class="mt-8">
              <Button
                type="submit"
                disabled={!createAccountHandler}
                class="disabled:opacity-50 disabled:cursor-default flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 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"
                handler={createAccountHandler}
              >
                <i18n.Translate>Create</i18n.Translate>
              </Button>
            </div>
          </form>
        </div>
      </div>
    </div>
  );
}

/**
 * Show the element when the load ended
 * @param element
 */
export function doAutoFocus(element: HTMLElement | null) {
  if (element) {
    setTimeout(() => {
      element.focus({ preventScroll: true });
      element.scrollIntoView({
        behavior: "smooth",
        block: "center",
        inline: "center",
      });
    }, 100);
  }
}
