/*
 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 {
  AmountString,
  Amounts,
  HttpStatusCode,
  OperationOk,
  OperationResult,
  TalerBankConversionApi,
  TranslatedString,
  assertUnreachable
} from "@gnu-taler/taler-util";
import {
  LocalNotificationBanner,
  ShowInputErrorLabel,
  useLocalNotification,
  useTranslationContext
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { useBankCoreApiContext } from "../context/config.js";
import { useBackendState } from "../hooks/backend.js";
import { RouteDefinition } from "../route.js";
import { ProfileNavigation } from "./ProfileNavigation.js";
import { useState } from "preact/hooks";
import { undefinedIfEmpty } from "../utils.js";
import { InputAmount } from "./PaytoWireTransferForm.js";

interface Props {
  routeMyAccountDetails: RouteDefinition;
  routeMyAccountDelete: RouteDefinition;
  routeMyAccountPassword: RouteDefinition;
  routeMyAccountCashout: RouteDefinition;
  routeConversionConfig: RouteDefinition;
  routeCancel: RouteDefinition;
  onUpdateSuccess: () => void;
}

type FormType<T> = {
  [k in keyof T]: string | undefined;
}

type ErrorsType<T> = {
  [k in keyof T]?: TranslatedString;
}


type FormHandler<T> = {
  [k in keyof T]?: {
    value: string | undefined;
    onUpdate: (s: string) => void;
    error: TranslatedString | undefined;
  }
}
function useFormState<T>(defaultValue: FormType<T>, validate: (f: FormType<T>) => ErrorsType<T>): FormHandler<T> {
  const [form, updateForm] = useState<FormType<T>>(defaultValue)

  const errors = undefinedIfEmpty<ErrorsType<T>>(validate(form))

  const p = (Object.keys(form) as Array<keyof T>)
  console.log("FORM", p)
  const handler = p.reduce((prev, fieldName) => {
    console.log("fie;d", fieldName)
    const currentValue = form[fieldName]
    const currentError = errors !== undefined ? errors[fieldName] : undefined
    prev[fieldName] = {
      error: currentError,
      value: currentValue,
      onUpdate: (newValue) => {
        updateForm({ ...form, [fieldName]: newValue })
      }
    }
    return prev
  }, {} as FormHandler<T>)

  return handler
}

/**
 * Show histories of public accounts.
 */
export function ConversionConfig({
  routeMyAccountCashout,
  routeMyAccountDelete,
  routeMyAccountDetails,
  routeMyAccountPassword,
  routeConversionConfig,
  routeCancel,
  onUpdateSuccess,
}: Props): VNode {
  const { i18n } = useTranslationContext();

  const { state: credentials } = useBackendState();
  const creds =
    credentials.status !== "loggedIn" || !credentials.isUserAdministrator
      ? undefined
      : credentials;
  const { api, config } = useBankCoreApiContext();

  const [notification, notify, handleError] = useLocalNotification();

  if (!creds) {
    return <div>only admin can setup conversion</div>;
  }

  const form = useFormState<TalerBankConversionApi.ConversionRate>({
    cashin_min_amount: undefined,
    cashin_tiny_amount: undefined,
    cashin_fee: undefined,
    cashin_ratio: undefined,
    cashin_rounding_mode: undefined,
    cashout_min_amount: undefined,
    cashout_tiny_amount: undefined,
    cashout_fee: undefined,
    cashout_ratio: undefined,
    cashout_rounding_mode: undefined,
  }, (state) => {
    return ({
      cashin_min_amount: !state.cashin_min_amount ? i18n.str`required` :
        !Amounts.parse(`${config.currency}:${state.cashin_min_amount}`) ? i18n.str`invalid` :
          undefined,

    })
  })


  async function doUpdate() {
    if (!creds) return
    await handleError(async () => {
      const resp = await api
        .getConversionInfoAPI()
        .updateConversionRate(creds.token, {

        } as any)
      if (resp.type === "ok") {
        onUpdateSuccess()
      } else {
        switch (resp.case) {
          case HttpStatusCode.Unauthorized: {
            return notify({
              type: "error",
              title: i18n.str`Wrong credentials`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
            });
          }
          case HttpStatusCode.NotImplemented: {
            return notify({
              type: "error",
              title: i18n.str`Conversion is disabled`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
            });
          }
          default:
            assertUnreachable(resp);
        }
      }
    });
  }


  return (
    <div>
      <ProfileNavigation current="conversion"
        routeMyAccountCashout={routeMyAccountCashout}
        routeMyAccountDelete={routeMyAccountDelete}
        routeMyAccountDetails={routeMyAccountDetails}
        routeMyAccountPassword={routeMyAccountPassword}
        routeConversionConfig={routeConversionConfig}
      />

      <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
        <LocalNotificationBanner notification={notification} />

        <div class="px-4 sm:px-0">
          <h2 class="text-base font-semibold leading-7 text-gray-900">
            <i18n.Translate>Conversion</i18n.Translate>
          </h2>
        </div>

        <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-6 pt-6">
            <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
                  for="cashout_amount_min"
                  class="block text-sm font-medium leading-6 text-gray-900"
                >{i18n.str`Minimum amount`}</label>
                <InputAmount
                  name="cashout_amount_min"
                  left
                  currency={config.currency}
                  value={form.cashin_min_amount?.value ?? ""}
                  onChange={form.cashin_min_amount?.onUpdate}
                />
                <ShowInputErrorLabel
                  message={form.cashin_min_amount?.error}
                  isDirty={form.cashin_min_amount?.value !== undefined}
                />
                <p class="mt-2 text-sm text-gray-500">
                  <i18n.Translate>Only cashout operation above this threshold will be allowed</i18n.Translate>
                </p>
              </div>
            </div>
          </div>

          <div class="px-6 pt-6">
            <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
                  for="cashout_amount_tiny"
                  class="block text-sm font-medium leading-6 text-gray-900"
                >{i18n.str`Minimum difference`}</label>
                <InputAmount
                  name="cashout_amount_tiny"
                  left
                  currency={config.currency}
                  value={form.cashin_min_amount?.value ?? ""}
                  onChange={form.cashin_min_amount?.onUpdate}
                />
                <ShowInputErrorLabel
                  message={form.cashin_min_amount?.error}
                  isDirty={form.cashin_min_amount?.value !== undefined}
                />
                <p class="mt-2 text-sm text-gray-500">
                  <i18n.Translate>Smallest difference between two amounts</i18n.Translate>
                </p>
              </div>
            </div>
          </div>

          <div class="px-6 pt-6">
            <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
                  for="cashin_fee"
                  class="block text-sm font-medium leading-6 text-gray-900"
                >{i18n.str`Fee`}</label>
                <InputAmount
                  name="cashin_fee"
                  left
                  currency={config.currency}
                  value={form.cashin_min_amount?.value ?? ""}
                  onChange={form.cashin_fee?.onUpdate}
                />
                <ShowInputErrorLabel
                  message={form.cashin_fee?.error}
                  isDirty={form.cashin_fee?.value !== undefined}
                />
                <p class="mt-2 text-sm text-gray-500">
                  <i18n.Translate>Operation fee</i18n.Translate>
                </p>
              </div>
            </div>
          </div>

          <div class="px-6 pt-6">
            <label
              class="block text-sm font-medium leading-6 text-gray-900"
              for="password"
            >
              {i18n.str`Ratio`}
            </label>
            <div class="mt-2">
              <input
                type="number"
                class="block w-full 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="current"
                id="cashout_ratio"
                data-error={!!form.cashin_ratio?.error && form.cashout_ratio?.value !== undefined}
                value={form.cashout_ratio?.value ?? ""}
                onChange={(e) => {
                  form.cashout_ratio?.onUpdate(e.currentTarget.value);
                }}
                autocomplete="off"
              />
              <ShowInputErrorLabel
                message={form.cashin_ratio?.error}
                isDirty={form.cashout_ratio?.value !== undefined}
              />
            </div>
            <p class="mt-2 text-sm text-gray-500">
              <i18n.Translate>
                Your current password, for security
              </i18n.Translate>
            </p>
          </div>

          <div class="flex items-center justify-between mt-6 gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
            <a name="cancel"
              href={routeCancel.url({})}
              class="text-sm font-semibold leading-6 text-gray-900"
            >
              <i18n.Translate>Cancel</i18n.Translate>
            </a>
            <button
              type="submit"
              name="update conversion"
              class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 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"
              onClick={async () => {
                doUpdate()
              }}
            >
              <i18n.Translate>Update</i18n.Translate>
            </button>
          </div>
        </form>
      </div>
    </div>
  );
}

