/*
 This file is part of GNU Taler
 (C) 2021-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 {
  Duration,
  HttpStatusCode,
  InstanceConfigurationMessage,
  MerchantAuthMethod,
  TanChannel,
} from "@gnu-taler/taler-util";
import {
  ButtonBetterBulma,
  LocalNotificationBannerBulma,
  undefinedIfEmpty,
  useChallengeHandler,
  useLocalNotificationBetter,
  useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import {
  FormErrors,
  FormProvider,
} from "../../components/form/FormProvider.js";
import { Input } from "../../components/form/Input.js";
import { InputToggle } from "../../components/form/InputToggle.js";
import { InputWithAddon } from "../../components/form/InputWithAddon.js";
import { SolveMFAChallenges } from "../../components/SolveMFA.js";
import { useSessionContext } from "../../context/session.js";
import {
  EMAIL_REGEX,
  INSTANCE_ID_REGEX,
  PHONE_JUST_NUMBERS_REGEX,
} from "../../utils/constants.js";

const TALER_SCREEN_ID = 80;

export interface Account {
  id: string;
  name: string;
  password: string;
  repeat: string;
  email: string;
  phone: string;
  tos: boolean;
}

const twoHours = Duration.fromSpec({ hours: 2 });
const oneDay = Duration.fromSpec({ days: 1 });
const twoDays = Duration.fromSpec({ days: 2 });

interface Props {
  onCancel: () => void;
  onCreated: () => void;
}
export function NewAccount({ onCancel, onCreated }: Props): VNode {
  const { i18n } = useTranslationContext();
  const { state: session, lib, logIn, config } = useSessionContext();

  const [value, setValue] = useState<Partial<Account>>({});

  const serverRequiresEmail =
    config.mandatory_tan_channels?.indexOf(TanChannel.EMAIL) !== -1;
  const serverRequiresSms =
    config.mandatory_tan_channels?.indexOf(TanChannel.SMS) !== -1;

  const errors = undefinedIfEmpty<FormErrors<Account>>({
    id: !value.id
      ? i18n.str`Required`
      : !INSTANCE_ID_REGEX.test(value.id)
        ? i18n.str`Invalid`
        : undefined,
    name: !value.name ? i18n.str`Required` : undefined,
    password: !value.password ? i18n.str`Required` : undefined,
    repeat: !value.repeat
      ? i18n.str`Required`
      : value.password !== value.repeat
        ? i18n.str`Doesn't match`
        : undefined,
    email: !serverRequiresEmail
      ? undefined
      : !value.email
        ? i18n.str`Required`
        : !EMAIL_REGEX.test(value.email)
          ? i18n.str`Doesn't have the pattern of an email`
          : undefined,
    phone: !serverRequiresSms
      ? undefined
      : !value.phone
        ? i18n.str`Required`
        : !value.phone.startsWith("+")
          ? i18n.str`Should start with +`
          : !PHONE_JUST_NUMBERS_REGEX.test(value.phone)
            ? i18n.str`A phone number consists of numbers only`
            : undefined,
    tos: !value.tos ? i18n.str`Required` : undefined,
  });

  function valueHandler(s: (d: Partial<Account>) => Partial<Account>): void {
    const next = s(value);
    const v: Account = {
      id: next.id ?? "",
      name: next.name ?? "",
      password: next.password ?? "",
      repeat: next.repeat ?? "",
      email: next.email ?? "",
      phone: next.phone ?? "",
      tos: next.tos ?? false,
    };
    setValue(v);
  }

  const [notification, safeFunctionHandler] = useLocalNotificationBetter();
  const mfa = useChallengeHandler();

  const request: InstanceConfigurationMessage = {
    address: {},
    auth: {
      method: MerchantAuthMethod.TOKEN,
      password: value.password!,
    },
    default_pay_delay:
      config.default_pay_delay ?? Duration.toTalerProtocolDuration(twoHours),
    default_wire_transfer_delay:
      config.default_wire_transfer_delay ??
      Duration.toTalerProtocolDuration(oneDay),
    default_refund_delay:
      config.default_refund_delay ?? Duration.toTalerProtocolDuration(twoDays),
    id: value.id!,
    jurisdiction: {},
    name: value.name!,
    use_stefan: true,
    email: value.email,
    phone_number: value.phone,
  };

  const create = safeFunctionHandler(
    (req: InstanceConfigurationMessage, challengeIds: string[]) =>
      lib.instance.createInstanceSelfProvision(req, {
        challengeIds,
        tokenValidity: Duration.fromSpec({ months: 6 }),
      }),
    !!errors ? undefined : [request, []],
  );
  create.onSuccess = (success, req) => {
    if (success) {
      logIn(req.id, success.access_token);
    }
    onCreated();
  };
  create.onFail = (fail) => {
    switch (fail.case) {
      case HttpStatusCode.Accepted:
        mfa.onChallengeRequired(fail.body);
        return undefined;
      case HttpStatusCode.Unauthorized:
        return i18n.str`Unauthorized`;
      case HttpStatusCode.Conflict:
        return i18n.str`There is another instance with this username.`;
    }
  };
  const retry = create.lambda((ids: string[]) => [create.args![0], ids]);

  if (mfa.pendingChallenge) {
    return (
      <SolveMFAChallenges
        currentChallenge={mfa.pendingChallenge}
        onCompleted={retry}
        onCancel={mfa.doCancelChallenge}
      />
    );
  }

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

      <div class="columns is-centered" style={{ margin: "auto" }}>
        <div class="column is-two-thirds ">
          <div class="modal-card" style={{ width: "100%", margin: 0 }}>
            <header
              class="modal-card-head"
              style={{ border: "1px solid", borderBottom: 0 }}
            >
              <p class="modal-card-title">
                <i18n.Translate>Self provision</i18n.Translate>
              </p>
            </header>
            <section
              class="modal-card-body"
              style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
            >
              <FormProvider<Account>
                name="settings"
                errors={errors}
                object={value}
                valueHandler={valueHandler}
              >
                <InputWithAddon<Account>
                  name="id"
                  label={i18n.str`Username`}
                  tooltip={i18n.str`Name of the instance in URLs. The 'admin' instance is special in that it is used to administer other instances.`}
                />

                <Input<Account>
                  name="name"
                  label={i18n.str`Business name`}
                  tooltip={i18n.str`Legal name of the business represented by this instance.`}
                />
                <Input<Account>
                  label={i18n.str`New password`}
                  tooltip={i18n.str`Next password to be used`}
                  inputType="password"
                  name="password"
                />
                <Input<Account>
                  label={i18n.str`Repeat password`}
                  tooltip={i18n.str`Confirm the same password`}
                  inputType="password"
                  name="repeat"
                />
                {serverRequiresEmail ? (
                  <Input<Account>
                    label={i18n.str`Email`}
                    tooltip={i18n.str`Contact email`}
                    name="email"
                  />
                ) : undefined}
                {serverRequiresSms ? (
                  <Input<Account>
                    label={i18n.str`Phone`}
                    tooltip={i18n.str`Contact phone number`}
                    name="phone"
                  />
                ) : undefined}
                <InputToggle
                  label={i18n.str`I agree`}
                  name="tos"
                  help={
                    <i18n.Translate>
                      <a
                        href="/terms"
                        target="_blank"
                        referrerpolicy="no-referrer"
                      >
                        <i18n.Translate>
                          Terms of service
                        </i18n.Translate>
                      </a>
                    </i18n.Translate>
                  }
                  tooltip={i18n.str`You must accept the Terms of service to continue.`}
                />
              </FormProvider>
            </section>
            <footer
              class="modal-card-foot "
              style={{
                justifyContent: "space-between",
                border: "1px solid",
                borderTop: 0,
              }}
            >
              <button class="button" type="button" onClick={onCancel}>
                <i18n.Translate>Cancel</i18n.Translate>
              </button>
              <ButtonBetterBulma onClick={create} type="submit">
                <i18n.Translate>Create</i18n.Translate>
              </ButtonBetterBulma>
            </footer>
          </div>
        </div>
      </div>
    </Fragment>
  );
}
