/*
 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,
  TalerProtocolTimestamp
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { isFuture, parse } from "date-fns";
import { useEffect, useState } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { Props, State } from "./index.js";

export function useComponentState({
  scope,
  onClose,
  onSuccess,
}: Props): State {
  const api = useBackendContext();
  const { pushAlertOnError } = useAlertContext();
  // const amount = Amounts.parseOrThrow(amountStr);
  const { i18n } = useTranslationContext();

  const [amount, setAmount] = useState<AmountJson>(Amounts.zeroOfCurrency(scope.currency));
  const [subject, setSubject] = useState<string | undefined>();
  const [timestamp, setTimestamp] = useState<string | undefined>();
  const amountStr = Amounts.stringify(amount)

  const hook = useAsyncAsHook(async () => {
    return await api.wallet.call(WalletApiOperation.CheckPeerPushDebit, {
      amount: amountStr,
      restrictScope: scope,
    });
  }, [amountStr]);

  const debitAmount = !hook || hook.hasError ? Amounts.zeroOfCurrency(scope.currency) : Amounts.parseOrThrow(hook.response.amountEffective);
  const toBeReceived = !hook || hook.hasError ? Amounts.zeroOfCurrency(scope.currency) : Amounts.parseOrThrow(hook.response.amountRaw);

  let purse_expiration: TalerProtocolTimestamp | undefined = undefined;
  let timestampError: string | undefined = undefined;

  const t =
    timestamp === undefined
      ? undefined
      : parse(timestamp, "dd/MM/yyyy", new Date());

  if (t !== undefined) {
    if (Number.isNaN(t.getTime())) {
      timestampError = 'Should have the format "dd/MM/yyyy"';
    } else {
      if (!isFuture(t)) {
        timestampError = "Should be in the future";
      } else {
        purse_expiration = {
          t_s: t.getTime() / 1000,
        };
      }
    }
  }

  async function accept(): Promise<void> {
    if (!subject || !purse_expiration) return;
    const resp = await api.wallet.call(
      WalletApiOperation.InitiatePeerPushDebit,
      {
        partialContractTerms: {
          summary: subject,
          amount: amountStr,
          purse_expiration,
        },
        restrictScope: scope,
      },
    );
    onSuccess(resp.transactionId);
  }

  const unableToCreate =
    !subject || Amounts.isZero(amount) || Amounts.isZero(debitAmount) || !purse_expiration;

  return {
    status: "ready",
    cancel: {
      onClick: pushAlertOnError(onClose),
    },
    amount: {
      value: amount,
      onInput: pushAlertOnError(async (e) => setAmount(e)),
      error: Amounts.isZero(amount) ? "Can't be zero" : undefined,
    },
    subject: {
      error:
        subject === undefined
          ? undefined
          : !subject
            ? "Can't be empty"
            : undefined,
      value: subject ?? "",
      onInput: pushAlertOnError(async (e) => setSubject(e)),
    },
    expiration: {
      error: timestampError,
      value: timestamp === undefined ? "" : timestamp,
      onInput: pushAlertOnError(async (e) => {
        setTimestamp(e);
      }),
    },
    create: {
      onClick: unableToCreate ? undefined : pushAlertOnError(accept),
    },
    debitAmount,
    toBeReceived,
    error: undefined,
  };
}

