import { ComponentChildren, VNode, h } from "preact";
import { ShowInputErrorLabel } from "../../components/ShowInputErrorLabel.js";
import { PartialButDefined, RecursivePartial, WithIntermediate, undefinedIfEmpty, validateIBAN } from "../../utils.js";
import { useEffect, useRef, useState } from "preact/hooks";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { buildPayto, parsePaytoUri } from "@gnu-taler/taler-util";

const IBAN_REGEX = /^[A-Z][A-Z0-9]*$/;
const EMAIL_REGEX =
  /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const REGEX_JUST_NUMBERS_REGEX = /^\+[0-9 ]*$/;

/**
 * Create valid account object to update or create
 * Take template as initial values for the form
 * Purpose indicate if all field al read only (show), part of them (update)
 * or none (create)
 * @param param0
 * @returns
 */
export function AccountForm({
  template,
  purpose,
  onChange,
  focus,
  children,
}: {
  focus?: boolean,
  children: ComponentChildren,
  template: SandboxBackend.Circuit.CircuitAccountData | undefined;
  onChange: (a: SandboxBackend.Circuit.CircuitAccountData | undefined) => void;
  purpose: "create" | "update" | "show";
}): VNode {
  const initial = initializeFromTemplate(template);
  const [form, setForm] = useState(initial);
  const [errors, setErrors] = useState<
    RecursivePartial<typeof initial> | undefined
  >(undefined);
  const { i18n } = useTranslationContext();
  const ref = useRef<HTMLInputElement>(null);
  useEffect(() => {
    if (focus) ref.current?.focus();
  }, [focus]);

  function updateForm(newForm: typeof initial): void {

    const parsed = !newForm.cashout_address
      ? undefined
      : buildPayto("iban", newForm.cashout_address, undefined);;

    const errors = undefinedIfEmpty<RecursivePartial<typeof initial>>({
      cashout_address: !newForm.cashout_address
        ? i18n.str`required`
        : !parsed
          ? i18n.str`does not follow the pattern`
          : !parsed.isKnown || parsed.targetType !== "iban"
            ? i18n.str`only "IBAN" target are supported`
            : !IBAN_REGEX.test(parsed.iban)
              ? i18n.str`IBAN should have just uppercased letters and numbers`
              : validateIBAN(parsed.iban, i18n),
      contact_data: undefinedIfEmpty({
        email: !newForm.contact_data?.email
          ? i18n.str`required`
          : !EMAIL_REGEX.test(newForm.contact_data.email)
            ? i18n.str`it should be an email`
            : undefined,
        phone: !newForm.contact_data?.phone
          ? i18n.str`required`
          : !newForm.contact_data.phone.startsWith("+")
            ? i18n.str`should start with +`
            : !REGEX_JUST_NUMBERS_REGEX.test(newForm.contact_data.phone)
              ? i18n.str`phone number can't have other than numbers`
              : undefined,
      }),
      // iban: !newForm.iban
      //   ? undefined //optional field
      //   : !IBAN_REGEX.test(newForm.iban)
      //     ? i18n.str`IBAN should have just uppercased letters and numbers`
      //     : validateIBAN(newForm.iban, i18n),
      name: !newForm.name ? i18n.str`required` : undefined,
      username: !newForm.username ? i18n.str`required` : undefined,
    });
    setErrors(errors);
    setForm(newForm);
    onChange(errors === undefined ? (newForm as any) : undefined);
  }

  return (
    <form
      class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
      autoCapitalize="none"
      autoCorrect="off"
      onSubmit={e => {
        e.preventDefault()
      }}
    >
      <div class="px-4 py-6 sm:p-8">
        <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">


          <div class="sm:col-span-5">
            <label
              class="block text-sm font-medium leading-6 text-gray-900"
              for="username"
            >
              {i18n.str`Username`}
              {purpose === "create" && <b style={{ color: "red" }}> *</b>}
            </label>
            <div class="mt-2">
              <input
                ref={ref}
                type="text"
                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                name="username"
                id="username"
                data-error={!!errors?.username && form.username !== undefined}
                disabled={purpose !== "create"}
                value={form.username ?? ""}
                onChange={(e) => {
                  form.username = e.currentTarget.value;
                  updateForm(structuredClone(form));
                }}
                // placeholder=""
                autocomplete="off"
              />
              <ShowInputErrorLabel
                message={errors?.username}
                isDirty={form.username !== undefined}
              />
            </div>
            <p class="mt-2 text-sm text-gray-500" >
              <i18n.Translate>account identification in the bank</i18n.Translate>
            </p>
          </div>

          <div class="sm:col-span-5">
            <label
              class="block text-sm font-medium leading-6 text-gray-900"
              for="name"
            >
              {i18n.str`Name`}
              {purpose === "create" && <b style={{ color: "red" }}> *</b>}
            </label>
            <div class="mt-2">
              <input
                type="text"
                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                name="name"
                data-error={!!errors?.name && form.name !== undefined}
                id="name"
                disabled={purpose !== "create"}
                value={form.name ?? ""}
                onChange={(e) => {
                  form.name = e.currentTarget.value;
                  updateForm(structuredClone(form));
                }}
                // placeholder=""
                autocomplete="off"
              />
              <ShowInputErrorLabel
                message={errors?.name}
                isDirty={form.name !== undefined}
              />
            </div>
            <p class="mt-2 text-sm text-gray-500" >
              <i18n.Translate>name of the person owner the account</i18n.Translate>
            </p>
          </div>


          {purpose !== "create" && (<div class="sm:col-span-5">
            <label
              class="block text-sm font-medium leading-6 text-gray-900"
              for="internal-iban"
            >
              {i18n.str`Internal IBAN`}
            </label>
            <div class="mt-2">
              <input
                type="text"
                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                name="internal-iban"
                id="internal-iban"
                disabled={true}
                value={form.iban ?? ""}
              />
            </div>
            <p class="mt-2 text-sm text-gray-500" >
              <i18n.Translate>international bank account number</i18n.Translate>
            </p>
          </div>)}

          <div class="sm:col-span-5">
            <label
              class="block text-sm font-medium leading-6 text-gray-900"
              for="email"
            >
              {i18n.str`Email`}
              {purpose === "create" && <b style={{ color: "red" }}> *</b>}
            </label>
            <div class="mt-2">
              <input
                type="email"
                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                name="email"
                id="email"
                data-error={!!errors?.contact_data?.email && form.contact_data.email !== undefined}
                disabled={purpose !== "create"}
                value={form.contact_data.email ?? ""}
                onChange={(e) => {
                  form.contact_data.email = e.currentTarget.value;
                  updateForm(structuredClone(form));
                }}
                autocomplete="off"
              />
              <ShowInputErrorLabel
                message={errors?.contact_data?.email}
                isDirty={form.contact_data.email !== undefined}
              />
            </div>
          </div>

          <div class="sm:col-span-5">
            <label
              class="block text-sm font-medium leading-6 text-gray-900"
              for="phone"
            >
              {i18n.str`Phone`}
              {purpose === "create" && <b style={{ color: "red" }}> *</b>}
            </label>
            <div class="mt-2">
              <input
                type="text"
                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                name="phone"
                id="phone"
                disabled={purpose !== "create"}
                value={form.contact_data.phone ?? ""}
                data-error={!!errors?.contact_data?.phone && form.contact_data.phone !== undefined}
                onChange={(e) => {
                  form.contact_data.phone = e.currentTarget.value;
                  updateForm(structuredClone(form));
                }}
                // placeholder=""
                autocomplete="off"
              />
              <ShowInputErrorLabel
                message={errors?.contact_data?.phone}
                isDirty={form.contact_data.phone !== undefined}
              />
            </div>
          </div>


          <div class="sm:col-span-5">
            <label
              class="block text-sm font-medium leading-6 text-gray-900"
              for="cashout"
            >
              {i18n.str`Cashout IBAN`}
              {purpose !== "show" && <b style={{ color: "red" }}> *</b>}
            </label>
            <div class="mt-2">
              <input
                type="text"
                data-error={!!errors?.cashout_address && form.cashout_address !== undefined}
                class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
                name="cashout"
                id="cashout"
                disabled={purpose === "show"}
                value={form.cashout_address ?? ""}
                onChange={(e) => {
                  form.cashout_address = e.currentTarget.value;
                  updateForm(structuredClone(form));
                }}
                autocomplete="off"
              />
              <ShowInputErrorLabel
                message={errors?.cashout_address}
                isDirty={form.cashout_address !== undefined}
              />
            </div>
            <p class="mt-2 text-sm text-gray-500" >
              <i18n.Translate>account number where the money is going to be sent when doing cashouts</i18n.Translate>
            </p>
          </div>

        </div>
      </div>
      {children}
    </form>
  );
}

function initializeFromTemplate(
  account: SandboxBackend.Circuit.CircuitAccountData | undefined,
): WithIntermediate<SandboxBackend.Circuit.CircuitAccountData> {
  const emptyAccount = {
    cashout_address: undefined,
    iban: undefined,
    name: undefined,
    username: undefined,
    contact_data: undefined,
  };
  const emptyContact = {
    email: undefined,
    phone: undefined,
  };

  const initial: PartialButDefined<SandboxBackend.Circuit.CircuitAccountData> =
    structuredClone(account) ?? emptyAccount;
  if (typeof initial.contact_data === "undefined") {
    initial.contact_data = emptyContact;
  }
  initial.contact_data.email;
  return initial as any;
}


