/*
 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 { HttpStatusCode } from "@gnu-taler/taler-util";
import {
  Attention,
  Button,
  LocalNotificationBanner,
  RouteDefinition,
  ShowInputErrorLabel,
  useChallengerApiContext,
  useLocalNotificationHandler,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { useSessionState } from "../hooks/session.js";
import { doAutoFocus } from "./AnswerChallenge.js";

type Form = {
  email: string;
};
export const EMAIL_REGEX = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/;

type Props = {
  nonce: string;
  onSendSuccesful: () => void;
  routeSolveChallenge: RouteDefinition<{ nonce: string }>;
  focus?: boolean;
};

export function AskChallenge({
  nonce,
  onSendSuccesful,
  routeSolveChallenge,
  focus,
}: Props): VNode {
  const { state, accepted, completed } = useSessionState();
  const status = state?.lastStatus;
  const prevEmail =
    !status || !status.last_address ? undefined : status.last_address["email"];
  const regexEmail =
    !status || !status.restrictions ? undefined : status.restrictions["email"];

  const { lib } = useChallengerApiContext();
  const { i18n } = useTranslationContext();
  const [notification, withErrorHandler] = useLocalNotificationHandler();
  const [email, setEmail] = useState<string | undefined>();
  const [repeat, setRepeat] = useState<string | undefined>();

  const regexTest =
    regexEmail && regexEmail.regex ? new RegExp(regexEmail.regex) : EMAIL_REGEX;
  const regexHint =
    regexEmail && regexEmail.hint ? regexEmail.hint : i18n.str`invalid email`;

  const errors = undefinedIfEmpty({
    email: !email
      ? i18n.str`required`
      : !regexTest.test(email)
        ? regexHint
        : prevEmail !== undefined && email === prevEmail
          ? i18n.str`email should be different`
          : undefined,
    repeat: !repeat
      ? i18n.str`required`
      : email !== repeat
        ? i18n.str`emails doesn't match`
        : undefined,
  });

  const onSend = errors
    ? undefined
    : withErrorHandler(
        async () => {
          return lib.challenger.challenge(nonce, { email: email! });
        },
        (ok) => {
          if ("redirectURL" in ok.body) {
            completed(ok.body.redirectURL);
          } else {
            accepted({
              attemptsLeft: ok.body.attempts_left,
              nextSend: ok.body.next_tx_time,
              transmitted: ok.body.transmitted,
            });
          }
          onSendSuccesful();
        },
        (fail) => {
          switch (fail.case) {
            case HttpStatusCode.BadRequest:
              return i18n.str``;
            case HttpStatusCode.NotFound:
              return i18n.str``;
            case HttpStatusCode.NotAcceptable:
              return i18n.str``;
            case HttpStatusCode.TooManyRequests:
              return i18n.str``;
            case HttpStatusCode.InternalServerError:
              return i18n.str``;
          }
        },
      );

  if (!status) {
    return <div>no status loaded</div>;
  }

  return (
    <Fragment>
      <LocalNotificationBanner notification={notification} />

      <div class="isolate bg-white px-6 py-12">
        <div class="mx-auto max-w-2xl text-center">
          <h2 class="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
            <i18n.Translate>Enter contact details</i18n.Translate>
          </h2>
          <p class="mt-2 text-lg leading-8 text-gray-600">
            <i18n.Translate>
              You will receive an email with a TAN code that must be provided on
              the next page.
            </i18n.Translate>
          </p>
        </div>
        {state.lastTry && (
          <Fragment>
            <Attention title={i18n.str`A code has been sent to ${prevEmail}`}>
              <i18n.Translate>
                <a href={routeSolveChallenge.url({ nonce })} class="underline">
                  <i18n.Translate>Complete the challenge here.</i18n.Translate>
                </a>
              </i18n.Translate>
            </Attention>
          </Fragment>
        )}
        <form
          method="POST"
          class="mx-auto mt-16 max-w-xl sm:mt-20"
          onSubmit={(e) => {
            e.preventDefault();
          }}
        >
          <div class="grid grid-cols-1 gap-x-8 gap-y-6">
            <div class="sm:col-span-2">
              <label
                for="email"
                class="block text-sm font-semibold leading-6 text-gray-900"
              >
                <i18n.Translate>Email</i18n.Translate>
              </label>
              <div class="mt-2.5">
                <input
                  type="email"
                  name="email"
                  id="email"
                  ref={focus ? doAutoFocus : undefined}
                  maxLength={512}
                  autocomplete="email"
                  value={email}
                  onChange={(e) => {
                    setEmail(e.currentTarget.value);
                  }}
                  placeholder={prevEmail}
                  readOnly={status.fix_address}
                  class="block w-full read-only:bg-slate-200 rounded-md border-0 px-3.5 py-2 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"
                />
                <ShowInputErrorLabel
                  message={errors?.email}
                  isDirty={email !== undefined}
                />
              </div>
            </div>

            {status.fix_address ? undefined : (
              <div class="sm:col-span-2">
                <label
                  for="repeat-email"
                  class="block text-sm font-semibold leading-6 text-gray-900"
                >
                  <i18n.Translate>Repeat email</i18n.Translate>
                </label>
                <div class="mt-2.5">
                  <input
                    type="email"
                    name="repeat-email"
                    id="repeat-email"
                    value={repeat}
                    onChange={(e) => {
                      setRepeat(e.currentTarget.value);
                    }}
                    autocomplete="email"
                    class="block w-full rounded-md border-0 px-3.5 py-2 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"
                  />
                  <ShowInputErrorLabel
                    message={errors?.repeat}
                    isDirty={repeat !== undefined}
                  />
                </div>
              </div>
            )}

            {!status.changes_left ? (
              <p class="mt-3 text-sm leading-6 text-gray-400">
                <i18n.Translate>No more changes left</i18n.Translate>
              </p>
            ) : (
              <p class="mt-3 text-sm leading-6 text-gray-400">
                <i18n.Translate>
                  You can change your email address another{" "}
                  {status.changes_left} times.
                </i18n.Translate>
              </p>
            )}
          </div>

          {!prevEmail ? (
            <div class="mt-10">
              <Button
                type="submit"
                disabled={!onSend}
                class="block w-full disabled:bg-gray-300 rounded-md bg-indigo-600 px-3.5 py-2.5 text-center 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"
                handler={onSend}
              >
                <i18n.Translate>Send email</i18n.Translate>
              </Button>
            </div>
          ) : (
            <div class="mt-10">
              <Button
                type="submit"
                disabled={!onSend}
                class="block w-full disabled:bg-gray-300 rounded-md bg-indigo-600 px-3.5 py-2.5 text-center 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"
                handler={onSend}
              >
                <i18n.Translate>Change email</i18n.Translate>
              </Button>
            </div>
          )}
        </form>
      </div>
    </Fragment>
  );
}

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