/*
 This file is part of GNU Taler
 (C) 2022 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 {
  AmountJson,
  Amounts,
  HttpStatusCode,
  Logger,
  TranslatedString,
  parseWithdrawUri
} from "@gnu-taler/taler-util";
import {
  notifyError,
  useLocalNotification,
  useTranslationContext
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { forwardRef } from "preact/compat";
import { useState } from "preact/hooks";
import { Attention } from "@gnu-taler/web-util/browser";
import { useBankCoreApiContext } from "../context/config.js";
import { useBackendState } from "../hooks/backend.js";
import { usePreferences } from "../hooks/preferences.js";
import { undefinedIfEmpty, withRuntimeErrorHandling } from "../utils.js";
import { OperationState } from "./OperationState/index.js";
import { InputAmount, doAutoFocus } from "./PaytoWireTransferForm.js";
import { assertUnreachable } from "./WithdrawalOperationPage.js";
import { LocalNotificationBanner } from "@gnu-taler/web-util/browser";

const logger = new Logger("WalletWithdrawForm");
const RefAmount = forwardRef(InputAmount);


function OldWithdrawalForm({ goToConfirmOperation, limit, onCancel, focus }: {
  limit: AmountJson;
  focus?: boolean;
  goToConfirmOperation: (operationId: string) => void;
  onCancel: () => void;
}): VNode {
  const { i18n } = useTranslationContext();
  const [settings, updateSettings] = usePreferences()

  const { state: credentials } = useBackendState();
  const creds = credentials.status !== "loggedIn" ? undefined : credentials

  const { api } = useBankCoreApiContext()
  const [amountStr, setAmountStr] = useState<string | undefined>(`${settings.maxWithdrawalAmount}`);
  const [notification, notify, handleError] = useLocalNotification()

  if (!!settings.currentWithdrawalOperationId) {
    return <Attention type="warning" title={i18n.str`There is an operation already`}>
      <span ref={focus ? doAutoFocus : undefined} />
      <i18n.Translate>
        To complete or cancel the operation click <a class="font-semibold text-yellow-700 hover:text-yellow-600" href={`#/operation/${settings.currentWithdrawalOperationId}`}>here</a>
      </i18n.Translate>
    </Attention>
  }

  const trimmedAmountStr = amountStr?.trim();

  const parsedAmount = trimmedAmountStr
    ? Amounts.parse(`${limit.currency}:${trimmedAmountStr}`)
    : undefined;

  const errors = undefinedIfEmpty({
    amount:
      trimmedAmountStr == null
        ? i18n.str`required`
        : !parsedAmount
          ? i18n.str`invalid`
          : Amounts.cmp(limit, parsedAmount) === -1
            ? i18n.str`balance is not enough`
            : undefined,
  });

  async function doStart() {
    if (!parsedAmount || !creds) return;
    await handleError(async () => {
      const resp = await api.createWithdrawal(creds, {
        amount: Amounts.stringify(parsedAmount),
      });
      if (resp.type === "ok") {
        const uri = parseWithdrawUri(resp.body.taler_withdraw_uri);
        if (!uri) {
          return notifyError(
            i18n.str`Server responded with an invalid  withdraw URI`,
            i18n.str`Withdraw URI: ${resp.body.taler_withdraw_uri}`);
        } else {
          updateSettings("currentWithdrawalOperationId", uri.withdrawalOperationId)
          goToConfirmOperation(uri.withdrawalOperationId);
        }
      } else {
        switch (resp.case) {
          case HttpStatusCode.Conflict: {
            notify({
              type: "error",
              title: i18n.str`The operation was rejected due to insufficient funds`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
            })
            break;
          }
          case HttpStatusCode.Unauthorized: {
            notify({
              type: "error",
              title: i18n.str`The operation was rejected due to insufficient funds`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
            })
            break;
          }
          case HttpStatusCode.NotFound: {
            notify({
              type: "error",
              title: i18n.str`Account not found`,
              description: resp.detail.hint as TranslatedString,
              debug: resp.detail,
            })
            break;
          }
          default: assertUnreachable(resp)
        }
      }
    })
  }

  return <form
    class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2 mt-4"
    autoCapitalize="none"
    autoCorrect="off"
    onSubmit={e => {
      e.preventDefault()
    }}
  >
    <LocalNotificationBanner notification={notification} />

    <div class="px-4 py-6 ">
      <div class="grid max-w-xs grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
        <div class="sm:col-span-5">
          <label for="withdraw-amount">{i18n.str`Amount`}</label>
          <RefAmount
            currency={limit.currency}
            value={amountStr}
            name="withdraw-amount"
            onChange={(v) => {
              setAmountStr(v);
            }}
            error={errors?.amount}
            ref={focus ? doAutoFocus : undefined}
          />
        </div>
      </div>
      <div class="mt-4">
        <div class="sm:inline">

          <button type="button"
            class="               inline-flex px-6 py-4 text-sm items-center rounded-l-md bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
            onClick={(e) => {
              e.preventDefault();
              setAmountStr("50.00")
            }}
          >
            50.00
          </button>
          <button type="button"
            class=" -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center rounded-r-md sm:rounded-none             bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
            onClick={(e) => {
              e.preventDefault();
              setAmountStr("25.00")
            }}
          >

            25.00
          </button>
        </div>
        <div class="mt-4 sm:inline">
          <button type="button"
            class=" -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center rounded-l-md sm:rounded-none             bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
            onClick={(e) => {
              e.preventDefault();
              setAmountStr("10.00")
            }}
          >
            10.00
          </button>
          <button type="button"
            class="               inline-flex px-6 py-4 text-sm items-center rounded-r-md bg-white  text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
            onClick={(e) => {
              e.preventDefault();
              setAmountStr("5.00")
            }}
          >
            5.00
          </button>
        </div>
      </div>
    </div>
    <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
      <button type="button" class="text-sm font-semibold leading-6 text-gray-900"
        onClick={onCancel}
      >
        <i18n.Translate>Cancel</i18n.Translate></button>
      <button type="submit"
        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"
        // disabled={isRawPayto ? !!errorsPayto : !!errorsWire}
        onClick={(e) => {
          e.preventDefault()
          doStart()
        }}
      >
        <i18n.Translate>Continue</i18n.Translate>
      </button>
    </div>

  </form>
}


export function WalletWithdrawForm({
  focus,
  limit,
  onCancel,
  goToConfirmOperation,
}: {
  limit: AmountJson;
  focus?: boolean;
  goToConfirmOperation: (operationId: string) => void;
  onCancel: () => void;
}): VNode {
  const { i18n } = useTranslationContext();
  const [settings, updateSettings] = usePreferences()

  return (<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">
    <div class="px-4 sm:px-0">
      <h2 class="text-base font-semibold leading-7 text-gray-900"><i18n.Translate>Prepare your wallet</i18n.Translate></h2>
      <p class="mt-1 text-sm text-gray-500">
        <i18n.Translate>After using your wallet you will need to confirm or cancel the operation on this site.</i18n.Translate>
      </p>
    </div>

    <div class="col-span-2">
      {settings.showInstallWallet &&
        <Attention title={i18n.str`You need a GNU Taler Wallet`} onClose={() => {
          updateSettings("showInstallWallet", false);
        }}>
          <i18n.Translate>
            If you don't have one yet you can follow the instruction <a target="_blank" rel="noreferrer noopener" class="font-semibold text-blue-700 hover:text-blue-600" href="https://taler.net/en/wallet.html">here</a>
          </i18n.Translate>
        </Attention>
      }

      {!settings.fastWithdrawal ?
        <OldWithdrawalForm
          focus={focus}
          limit={limit}
          onCancel={onCancel}
          goToConfirmOperation={goToConfirmOperation}
        />
        :
        <OperationState
          currency={limit.currency}
          onClose={onCancel}
        />
      }
    </div>
  </div>
  );
}

