/*
 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, Logger } from "@gnu-taler/taler-util";
import {
  RequestError,
  useTranslationContext,
} from "@gnu-taler/web-util/lib/index.browser";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { useBackendContext } from "../context/backend.js";
import { PageStateType } from "../context/pageState.js";
import { useTestingAPI } from "../hooks/access.js";
import { bankUiSettings } from "../settings.js";
import { undefinedIfEmpty } from "../utils.js";
import { ShowInputErrorLabel } from "./ShowInputErrorLabel.js";

const logger = new Logger("RegistrationPage");

export function RegistrationPage({
  onError,
  onComplete,
}: {
  onComplete: () => void;
  onError: (e: PageStateType["error"]) => void;
}): VNode {
  const { i18n } = useTranslationContext();
  if (!bankUiSettings.allowRegistrations) {
    return (
      <p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p>
    );
  }
  return <RegistrationForm onComplete={onComplete} onError={onError} />;
}

export const USERNAME_REGEX = /^[a-z][a-zA-Z0-9]*$/;
export const PASSWORD_REGEX = /^[a-z0-9][a-zA-Z0-9]*$/;

/**
 * Collect and submit registration data.
 */
function RegistrationForm({
  onComplete,
  onError,
}: {
  onComplete: () => void;
  onError: (e: PageStateType["error"]) => void;
}): VNode {
  const backend = useBackendContext();
  const [username, setUsername] = useState<string | undefined>();
  const [password, setPassword] = useState<string | undefined>();
  const [repeatPassword, setRepeatPassword] = useState<string | undefined>();

  const { register } = useTestingAPI();
  const { i18n } = useTranslationContext();

  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`
      : !PASSWORD_REGEX.test(password)
      ? i18n.str`Use letters and numbers only, and start with a lowercase letter or number`
      : undefined,
    repeatPassword: !repeatPassword
      ? i18n.str`Missing password`
      : repeatPassword !== password
      ? i18n.str`Passwords don't match`
      : undefined,
  });

  return (
    <Fragment>
      <h1 class="nav">{i18n.str`Welcome to ${bankUiSettings.bankName}!`}</h1>
      <article>
        <div class="register-div">
          <form
            class="register-form"
            noValidate
            onSubmit={(e) => {
              e.preventDefault();
            }}
            autoCapitalize="none"
            autoCorrect="off"
          >
            <div class="pure-form">
              <h2>{i18n.str`Please register!`}</h2>
              <p class="unameFieldLabel registerFieldLabel formFieldLabel">
                <label for="register-un">{i18n.str`Username:`}</label>
              </p>
              <input
                id="register-un"
                name="register-un"
                type="text"
                placeholder="Username"
                autocomplete="username"
                value={username ?? ""}
                onInput={(e): void => {
                  setUsername(e.currentTarget.value);
                }}
              />
              <ShowInputErrorLabel
                message={errors?.username}
                isDirty={username !== undefined}
              />
              <p class="unameFieldLabel registerFieldLabel formFieldLabel">
                <label for="register-pw">{i18n.str`Password:`}</label>
              </p>
              <input
                type="password"
                name="register-pw"
                id="register-pw"
                placeholder="Password"
                autocomplete="new-password"
                value={password ?? ""}
                required
                onInput={(e): void => {
                  setPassword(e.currentTarget.value);
                }}
              />
              <ShowInputErrorLabel
                message={errors?.password}
                isDirty={password !== undefined}
              />
              <p class="unameFieldLabel registerFieldLabel formFieldLabel">
                <label for="register-repeat">{i18n.str`Repeat Password:`}</label>
              </p>
              <input
                type="password"
                style={{ marginBottom: 8 }}
                name="register-repeat"
                id="register-repeat"
                autocomplete="new-password"
                placeholder="Same password"
                value={repeatPassword ?? ""}
                required
                onInput={(e): void => {
                  setRepeatPassword(e.currentTarget.value);
                }}
              />
              <ShowInputErrorLabel
                message={errors?.repeatPassword}
                isDirty={repeatPassword !== undefined}
              />
              <br />
              <button
                class="pure-button pure-button-primary btn-register"
                type="submit"
                disabled={!!errors}
                onClick={async (e) => {
                  e.preventDefault();

                  if (!username || !password) return;
                  try {
                    const credentials = { username, password };
                    await register(credentials);
                    setUsername(undefined);
                    setPassword(undefined);
                    setRepeatPassword(undefined);
                    backend.logIn(credentials);
                    onComplete();
                  } catch (error) {
                    if (error instanceof RequestError) {
                      const errorData: SandboxBackend.SandboxError =
                        error.info.error;
                      if (error.info.status === HttpStatusCode.Conflict) {
                        onError({
                          title: i18n.str`That username is already taken`,
                          description: errorData.error.description,
                          debug: JSON.stringify(error.info),
                        });
                      } else {
                        onError({
                          title: i18n.str`New registration gave response error`,
                          description: errorData.error.description,
                          debug: JSON.stringify(error.info),
                        });
                      }
                    } else if (error instanceof Error) {
                      onError({
                        title: i18n.str`Registration failed, please report`,
                        description: error.message,
                      });
                    }
                  }
                }}
              >
                {i18n.str`Register`}
              </button>
              {/* FIXME: should use a different color */}
              <button
                class="pure-button pure-button-secondary btn-cancel"
                onClick={(e) => {
                  e.preventDefault();
                  setUsername(undefined);
                  setPassword(undefined);
                  setRepeatPassword(undefined);
                  onComplete();
                }}
              >
                {i18n.str`Cancel`}
              </button>
            </div>
          </form>
        </div>
      </article>
    </Fragment>
  );
}
