/*
 This file is part of GNU Taler
 (C) 2021-2023 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/>
 */

/**
 *
 * @author Sebastian Javier Marchano (sebasjm)
 */

import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AsyncButton } from "../../../components/exception/AsyncButton.js";
import {
  FormErrors,
  FormProvider,
} from "../../../components/form/FormProvider.js";
import { DefaultInstanceFormFields } from "../../../components/instance/DefaultInstanceFormFields.js";
import { MerchantBackend } from "../../../declaration.js";
import { INSTANCE_ID_REGEX } from "../../../utils/constants.js";
import { undefinedIfEmpty } from "../../../utils/table.js";
import { SetTokenNewInstanceModal } from "../../../components/modal/index.js";
import { Duration } from "@gnu-taler/taler-util";

export type Entity = Omit<Omit<MerchantBackend.Instances.InstanceConfigurationMessage, "default_pay_delay">, "default_wire_transfer_delay"> & {
  auth_token?: string;
  default_pay_delay: Duration,
  default_wire_transfer_delay: Duration,
};

interface Props {
  onCreate: (d: MerchantBackend.Instances.InstanceConfigurationMessage) => Promise<void>;
  onBack?: () => void;
  forceId?: string;
}

function with_defaults(id?: string): Partial<Entity> {
  return {
    id,
    // accounts: [],
    user_type: "business",
    use_stefan: true,
    default_pay_delay: { d_ms: 2 * 60 * 60 * 1000 }, // two hours
    default_wire_transfer_delay: { d_ms: 2 * 60 * 60 * 24 * 1000 }, // two days
  };
}

export function CreatePage({ onCreate, onBack, forceId }: Props): VNode {
  const [value, valueHandler] = useState(with_defaults(forceId));
  const [isTokenSet, updateIsTokenSet] = useState<boolean>(false);
  const [isTokenDialogActive, updateIsTokenDialogActive] =
    useState<boolean>(false);

  const { i18n } = useTranslationContext();

  const errors: FormErrors<Entity> = {
    id: !value.id
      ? i18n.str`required`
      : !INSTANCE_ID_REGEX.test(value.id)
        ? i18n.str`is not valid`
        : undefined,
    name: !value.name ? i18n.str`required` : undefined,

    user_type: !value.user_type
      ? i18n.str`required`
      : value.user_type !== "business" && value.user_type !== "individual"
        ? i18n.str`should be business or individual`
        : undefined,
    // accounts:
    //   !value.accounts || !value.accounts.length
    //     ? i18n.str`required`
    //     : undefinedIfEmpty(
    //       value.accounts.map((p) => {
    //         return !PAYTO_REGEX.test(p.payto_uri)
    //           ? i18n.str`is not valid`
    //           : undefined;
    //       }),
    //     ),
    default_pay_delay: !value.default_pay_delay
      ? i18n.str`required`
      : !!value.default_wire_transfer_delay &&
        value.default_wire_transfer_delay.d_ms !== "forever" &&
        value.default_pay_delay.d_ms !== "forever" &&
        value.default_pay_delay.d_ms > value.default_wire_transfer_delay.d_ms ?
        i18n.str`pay delay can't be greater than wire transfer delay` : undefined,
    default_wire_transfer_delay: !value.default_wire_transfer_delay
      ? i18n.str`required`
      : undefined,
    address: undefinedIfEmpty({
      address_lines:
        value.address?.address_lines && value.address?.address_lines.length > 7
          ? i18n.str`max 7 lines`
          : undefined,
    }),
    jurisdiction: undefinedIfEmpty({
      address_lines:
        value.address?.address_lines && value.address?.address_lines.length > 7
          ? i18n.str`max 7 lines`
          : undefined,
    }),
  };

  const hasErrors = Object.keys(errors).some(
    (k) => (errors as any)[k] !== undefined,
  );

  const submit = (): Promise<void> => {
    // use conversion instead of this
    const newValue = structuredClone(value);

    const newToken = newValue.auth_token;
    newValue.auth_token = undefined;
    newValue.auth = newToken === null || newToken === undefined
      ? { method: "external" }
      : { method: "token", token: `secret-token:${newToken}` };
    if (!newValue.address) newValue.address = {};
    if (!newValue.jurisdiction) newValue.jurisdiction = {};
    // remove above use conversion
    // schema.validateSync(value, { abortEarly: false })
    newValue.default_pay_delay = Duration.toTalerProtocolDuration(newValue.default_pay_delay!) as any
    newValue.default_wire_transfer_delay = Duration.toTalerProtocolDuration(newValue.default_wire_transfer_delay!) as any
    // delete value.default_pay_delay;
    // delete value.default_wire_transfer_delay;

    return onCreate(newValue as any as MerchantBackend.Instances.InstanceConfigurationMessage);
  };

  function updateToken(token: string | null) {
    valueHandler((old) => ({
      ...old,
      auth_token: token === null ? undefined : token,
    }));
  }

  return (
    <div>
      <div class="columns">
        <div class="column" />
        <div class="column is-four-fifths">
          {isTokenDialogActive && (
            <SetTokenNewInstanceModal
              onCancel={() => {
                updateIsTokenDialogActive(false);
                updateIsTokenSet(false);
              }}
              onClear={() => {
                updateToken(null);
                updateIsTokenDialogActive(false);
                updateIsTokenSet(true);
              }}
              onConfirm={(newToken) => {
                updateToken(newToken);
                updateIsTokenDialogActive(false);
                updateIsTokenSet(true);
              }}
            />
          )}
        </div>
        <div class="column" />
      </div>

      <section class="section is-main-section">
        <div class="columns">
          <div class="column" />
          <div class="column is-four-fifths">
            <FormProvider<Entity>
              errors={errors}
              object={value}
              valueHandler={valueHandler}
            >
              <DefaultInstanceFormFields readonlyId={!!forceId} showId={true} />
            </FormProvider>

            <div class="level">
              <div class="level-item has-text-centered">
                <h1 class="title">
                  <button
                    class={
                      !isTokenSet
                        ? "button is-danger has-tooltip-bottom"
                        : !value.auth_token
                          ? "button has-tooltip-bottom"
                          : "button is-info has-tooltip-bottom"
                    }
                    data-tooltip={i18n.str`change authorization configuration`}
                    onClick={() => updateIsTokenDialogActive(true)}
                  >
                    <div class="icon is-centered">
                      <i class="mdi mdi-lock-reset" />
                    </div>
                    <span>
                      <i18n.Translate>Set access token</i18n.Translate>
                    </span>
                  </button>
                </h1>
              </div>
            </div>
            <div class="level">
              <div class="level-item has-text-centered">
                {!isTokenSet ? (
                  <p class="is-size-6">
                    <i18n.Translate>
                      Access token is not yet configured. This instance can't be
                      created.
                    </i18n.Translate>
                  </p>
                ) : value.auth_token === undefined ? (
                  <p class="is-size-6">
                    <i18n.Translate>
                      No access token. Authorization must be handled externally.
                    </i18n.Translate>
                  </p>
                ) : (
                  <p class="is-size-6">
                    <i18n.Translate>
                      Access token is set. Authorization is handled by the
                      merchant backend.
                    </i18n.Translate>
                  </p>
                )}
              </div>
            </div>
            <div class="buttons is-right mt-5">
              {onBack && (
                <button class="button" onClick={onBack}>
                  <i18n.Translate>Cancel</i18n.Translate>
                </button>
              )}
              <AsyncButton
                onClick={submit}
                disabled={hasErrors || !isTokenSet}
                data-tooltip={
                  hasErrors
                    ? i18n.str`Need to complete marked fields and choose authorization method`
                    : "confirm operation"
                }
              >
                <i18n.Translate>Confirm</i18n.Translate>
              </AsyncButton>
            </div>
          </div>
          <div class="column" />
        </div>
      </section>
    </div>
  );
}
