/*
 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/>
 */

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

import {
  assertUnreachable,
  Duration,
  LoginTokenScope,
  TalerMerchantApi,
} from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
import {
  FormErrors,
  FormProvider,
  TalerForm,
} from "../../../../components/form/FormProvider.js";
import { Input } from "../../../../components/form/Input.js";
import { InputDuration } from "../../../../components/form/InputDuration.js";
import { InputSelector } from "../../../../components/form/InputSelector.js";
import { undefinedIfEmpty } from "../../../../utils/table.js";

type Entity = {
  scope: TalerMerchantApi.LoginTokenRequest["scope"];
  duration: Duration;
  description: string;
  password: string;
} & TalerForm;

interface Props {
  onCreate: (
    pwd: string,
    d: TalerMerchantApi.LoginTokenRequest,
  ) => Promise<void>;
  onBack?: () => void;
}

const VALID_TOKEN_SCOPE = [
  "",
  LoginTokenScope.ReadOnly,
  LoginTokenScope.OrderSimple,
  LoginTokenScope.OrderPos,
  LoginTokenScope.OrderManagement,
  LoginTokenScope.OrderFull,
  // LoginTokenScope.All_Refreshable,
  LoginTokenScope.ReadOnly_Refreshable,
  LoginTokenScope.OrderSimple_Refreshable,
  LoginTokenScope.OrderPos_Refreshable,
  LoginTokenScope.OrderManagement_Refreshable,
  LoginTokenScope.OrderFull_Refreshable,
  LoginTokenScope.All,
];

export function CreatePage({ onCreate, onBack }: Props): VNode {
  const { i18n } = useTranslationContext();

  const [state, setState] = useState<Partial<Entity>>({});

  const errors = undefinedIfEmpty<FormErrors<Entity>>({
    password: !state.password ? i18n.str`Required` : undefined,
    duration: !state.duration ? i18n.str`Required` : undefined,
    description: !state.description ? i18n.str`Required` : undefined,
    scope: !state.scope ? i18n.str`Required` : undefined,
  });

  const hasErrors = errors !== undefined;

  const submitForm = () => {
    if (hasErrors) return Promise.reject();

    return onCreate(state.password!, {
      scope: state.scope!,
      duration: Duration.toTalerProtocolDuration(state.duration!),
      description: state.description!,
    });
  };

  return (
    <Fragment>
      <section class="section is-main-section">
        <div class="columns">
          <div class="column" />
          <div class="column is-four-fifths">
            <FormProvider
              object={state}
              valueHandler={setState}
              errors={errors}
            >
              <Input<Entity>
                name="description"
                label={i18n.str`Description`}
                help={i18n.str`Helps you remember where this token is being used before deleting it.`}
              />

              <InputDuration<Entity>
                name="duration"
                label={i18n.str`Duration`}
                withForever
                tooltip={i18n.str`Time the access token will be valid.`}
              />
              <InputSelector
                name="scope"
                label={i18n.str`Scope`}
                tooltip={i18n.str`The scope defines the set of permissions for the access token. Refreshable tokens has the permission to extend the expiration time.`}
                values={VALID_TOKEN_SCOPE}
                help={((s) => {
                  if (!s) return ""
                  switch (s) {
                    case LoginTokenScope.All:
                      return i18n.str`Allows all operations without limit.`
                    case LoginTokenScope.ReadOnly:
                      return i18n.str`Allows all operations to read information.`
                    case LoginTokenScope.OrderSimple:
                      return i18n.str`Allows the creation of orders and checking of payment status.`
                    case LoginTokenScope.OrderPos:
                      return i18n.str`Allows the creation of orders, checking of payment status and inventory locking.`
                    case LoginTokenScope.OrderManagement:
                      return i18n.str`Allows the creation of orders, checking of payment status and refunds.`
                    case LoginTokenScope.OrderFull:
                      return i18n.str`Allows the creation of orders, checking of payment status, inventory locking and refunds.`
                    case LoginTokenScope.ReadOnly_Refreshable:
                      return i18n.str`Allows all operations to read information with extendable expiration time.`
                    case LoginTokenScope.OrderSimple_Refreshable:
                      return i18n.str`Allows the creation of orders and checking of payment status with extendable expiration time.`
                    case LoginTokenScope.OrderPos_Refreshable:
                      return i18n.str`Allows the creation of orders, checking of payment status and inventory locking with extendable expiration time.`
                    case LoginTokenScope.OrderManagement_Refreshable:
                      return i18n.str`Allows the creation of orders, checking of payment status and refunds with extendable expiration time.`
                    case LoginTokenScope.OrderFull_Refreshable:
                      return i18n.str`Allows the creation of orders, checking of payment status, inventory locking and refunds with extendable expiration time.`
                    case LoginTokenScope.All_Refreshable:
                      return i18n.str`All (refreshable)`;
                    case LoginTokenScope.Spa:
                      return i18n.str`Spa`;
                    case LoginTokenScope.Spa_Refreshable:
                      return i18n.str`Spa (refreshable)`;
                    default: {
                      assertUnreachable(s);
                    }
                  }
                })(state.scope)}
                toStr={(str) => {
                  if (!str) {
                    return i18n.str`Choose one`
                  }
                  const s = str as LoginTokenScope;
                  switch (s) {
                    case LoginTokenScope.ReadOnly:
                      return i18n.str`Read only`;
                    case LoginTokenScope.All:
                      return i18n.str`All`;
                    case LoginTokenScope.OrderSimple:
                      return i18n.str`Order simple`;
                    case LoginTokenScope.OrderPos:
                      return i18n.str`Order Point-of-Sale`;
                    case LoginTokenScope.OrderManagement:
                      return i18n.str`Order management`;
                    case LoginTokenScope.OrderFull:
                      return i18n.str`Order full`;
                    case LoginTokenScope.ReadOnly_Refreshable:
                      return i18n.str`Read only (refreshable)`;
                    case LoginTokenScope.OrderSimple_Refreshable:
                      return i18n.str`Order simple (refreshable)`;
                    case LoginTokenScope.OrderPos_Refreshable:
                      return i18n.str`Order Point-of-Sale (refreshable)`;
                    case LoginTokenScope.OrderManagement_Refreshable:
                      return i18n.str`Order management (refreshable)`;
                    case LoginTokenScope.OrderFull_Refreshable:
                      return i18n.str`Order full (refreshable)`;
                    case LoginTokenScope.All_Refreshable:
                      return i18n.str`All (refreshable)`;
                    case LoginTokenScope.Spa:
                      return i18n.str`Spa`;
                    case LoginTokenScope.Spa_Refreshable:
                      return i18n.str`Spa (refreshable)`;
                    default: {
                      assertUnreachable(s);
                    }
                  }
                }}
              />
              <Input<Entity>
                name="password"
                inputType="password"
                label={i18n.str`Current password`}
              />


            </FormProvider>
            <div class="buttons is-right mt-5">
              {onBack && (
                <button class="button" onClick={onBack}>
                  <i18n.Translate>Cancel</i18n.Translate>
                </button>
              )}
              <AsyncButton
                disabled={hasErrors}
                data-tooltip={
                  hasErrors
                    ? i18n.str`Please complete the marked fields`
                    : i18n.str`Confirm operation`
                }
                onClick={submitForm}
              >
                <i18n.Translate>Confirm</i18n.Translate>
              </AsyncButton>
            </div>
          </div>
          <div class="column" />
        </div>
      </section>
    </Fragment>
  );
}
