/*
 This file is part of GNU Taler
 (C) 2022 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, TranslatedString } from "@gnu-taler/taler-util";
import { ErrorType, notifyError, useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
import { useBackendContext } from "../context/backend.js";
import { bankUiSettings } from "../settings.js";
import { undefinedIfEmpty } from "../utils.js";
import { USERNAME_REGEX } from "./RegistrationPage.js";
import { ShowInputErrorLabel } from "../components/ShowInputErrorLabel.js";
import { AccessToken, useCredentialsChecker } from "../hooks/useCredentialsChecker.js";
import { useCredentialsCheckerOld } from "../hooks/backend.js";

/**
 * Collect and submit login data.
 */
export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode {
  const backend = useBackendContext();
  const currentUser = backend.state.status === "loggedIn" ? backend.state.username : undefined
  const [username, setUsername] = useState<string | undefined>(currentUser);
  const [password, setPassword] = useState<string | undefined>();
  const { i18n } = useTranslationContext();
  const { requestNewLoginToken, refreshLoginToken } = useCredentialsChecker();

  // const testLogin = useCredentialsCheckerOld();
  const ref = useRef<HTMLInputElement>(null);
  useEffect(function focusInput() {
    ref.current?.focus();
  }, []);
  const [busy, setBusy] = useState<Record<string, undefined>>()

  const errors = undefinedIfEmpty({
    username: !username
      ? i18n.str`Missing username`
      // : !USERNAME_REGEX.test(username)
      //   ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
      : undefined,
    password: !password ? i18n.str`Missing password` : undefined,
  }) ?? busy;

  function saveError({ title, description, debug }: { title: TranslatedString, description?: TranslatedString, debug?: any }) {
    notifyError(title, description, debug)
  }

  async function doLogin() {
    if (!username || !password) return;
    setBusy({})
    const result = await requestNewLoginToken(username, password);
    if (result.valid) {
      backend.logIn({ username, password });
    } else {
      const { cause } = result;
      switch (cause.type) {
        case ErrorType.CLIENT: {
          if (cause.status === HttpStatusCode.Unauthorized) {
            saveError({
              title: i18n.str`Wrong credentials for "${username}"`,
            });
          } else
            if (cause.status === HttpStatusCode.NotFound) {
              saveError({
                title: i18n.str`Account not found`,
              });
            } else {
              saveError({
                title: i18n.str`Could not load due to a client error`,
                // description: cause.payload.error.description,
                debug: JSON.stringify(cause.payload),
              });
            }
          break;
        }
        case ErrorType.SERVER: {
          saveError({
            title: i18n.str`Server had a problem, try again later or report.`,
            // description: cause.payload.error.description,
            debug: JSON.stringify(cause.payload),
          });
          break;
        }
        case ErrorType.TIMEOUT: {
          saveError({
            title: i18n.str`Request timeout, try again later.`,
          });
          break;
        }
        case ErrorType.UNREADABLE: {
          saveError({
            title: i18n.str`Unexpected error.`,
            description: `Response from ${cause.info?.url} is unreadable, http status: ${cause.status}` as TranslatedString,
            debug: JSON.stringify(cause),
          });
          break;
        }
        default: {
          saveError({
            title: i18n.str`Unexpected error, please report.`,
            description: `Diagnostic from ${cause.info?.url} is "${cause.message}"` as TranslatedString,
            debug: JSON.stringify(cause),
          });
          break;
        }
      }
      // backend.logOut();
    }
    setPassword(undefined);
    setBusy(undefined)
  }

  return (
    <Fragment>
      <h1 class="nav"></h1>
      {/* {error && (
        <ErrorBannerFloat error={error} onClear={() => saveError(undefined)} />
      )} */}

      <div class="flex min-h-full flex-col justify-center">
        <div class="sm:mx-auto sm:w-full sm:max-w-sm">
          <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h2>
        </div>

        <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
          <form class="space-y-6" noValidate
            onSubmit={(e) => {
              e.preventDefault();
            }}
            autoCapitalize="none"
            autoCorrect="off"
          >
            <div>
              <label for="username" class="block text-sm font-medium leading-6 text-gray-900">
                <i18n.Translate>Username</i18n.Translate>
              </label>
              <div class="mt-2">
                <input
                  ref={ref}
                  autoFocus
                  type="text"
                  name="username"
                  id="username"
                  class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  value={username ?? ""}
                  enterkeyhint="next"
                  placeholder="identification"
                  autocomplete="username"
                  required
                  onInput={(e): void => {
                    setUsername(e.currentTarget.value);
                  }}
                />
                <ShowInputErrorLabel
                  message={errors?.username}
                  isDirty={username !== undefined}
                />
              </div>
            </div>

            <div>
              <div class="flex items-center justify-between">
                <label for="password" class="block text-sm font-medium leading-6 text-gray-900">Password</label>
              </div>
              <div class="mt-2">
                <input
                  type="password"
                  name="password"
                  id="password"
                  autocomplete="current-password"
                  class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                  enterkeyhint="send"
                  value={password ?? ""}
                  placeholder="Password"
                  required
                  onInput={(e): void => {
                    setPassword(e.currentTarget.value);
                  }}
                />
                <ShowInputErrorLabel
                  message={errors?.password}
                  isDirty={password !== undefined}
                />
              </div>
            </div>

            <div>
              <button type="submit"
                class="flex w-full justify-center rounded-md bg-indigo-600 disabled:bg-gray-300 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"
                disabled={!!errors}
                onClick={(e) => {
                  e.preventDefault()
                  doLogin()
                }}
              >
                <i18n.Translate>Log in</i18n.Translate>
              </button>
            </div>
          </form>

          {bankUiSettings.allowRegistrations && onRegister &&
            <p class="mt-10 text-center text-sm text-gray-500 border-t">
              <button type="submit"
                class="flex mt-4 rounded-md bg-blue-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
                onClick={(e) => {
                  e.preventDefault()
                  onRegister()
                }}
              >
                <i18n.Translate>Register</i18n.Translate>
              </button>
            </p>
          }
        </div>
      </div>


    </Fragment>
  );
}
