/*
 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 
 */
import {
  Amounts,
  ConfirmPayResultType,
  NotificationType,
  PreparePayResultType,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useEffect } from "preact/hooks";
import { alertFromError, useAlertContext } from "../../context/alert.js";
import { useBackendContext } from "../../context/backend.js";
import { useTranslationContext } from "../../context/translation.js";
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
import { ButtonHandler } from "../../mui/handlers.js";
import { Props, State } from "./index.js";
export function useComponentState({
  talerPayUri,
  cancel,
  goToWalletManualWithdraw,
  onSuccess,
}: Props): State {
  const { pushAlertOnError } = useAlertContext();
  const api = useBackendContext();
  const { i18n } = useTranslationContext();
  const hook = useAsyncAsHook(async () => {
    if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT");
    const payStatus = await api.wallet.call(
      WalletApiOperation.PreparePayForUri,
      {
        talerPayUri: talerPayUri,
      },
    );
    const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
    return { payStatus, balance, uri: talerPayUri };
  }, []);
  useEffect(
    () =>
      api.listener.onUpdateNotification(
        [NotificationType.CoinWithdrawn],
        hook?.retry,
      ),
    [hook],
  );
  const hookResponse = !hook || hook.hasError ? undefined : hook.response;
  useEffect(() => {
    if (!hookResponse) return;
    const { payStatus } = hookResponse;
    if (
      payStatus &&
      payStatus.status === PreparePayResultType.AlreadyConfirmed &&
      payStatus.paid
    ) {
      const fu = payStatus.contractTerms.fulfillment_url;
      if (fu) {
        setTimeout(() => {
          document.location.href = fu;
        }, 3000);
      }
    }
  }, [hookResponse]);
  if (!hook) return { status: "loading", error: undefined };
  if (hook.hasError) {
    return {
      status: "error",
      error: alertFromError(
        i18n.str`Could not load the status of the term of service`,
        hook,
      ),
    };
  }
  // if (hook.hasError) {
  //   return {
  //     status: "loading-uri",
  //     error: hook,
  //   };
  // }
  const { payStatus } = hook.response;
  const amount = Amounts.parseOrThrow(payStatus.amountRaw);
  const foundBalance = hook.response.balance.balances.find(
    (b) => Amounts.parseOrThrow(b.available).currency === amount.currency,
  );
  const baseResult = {
    uri: hook.response.uri,
    amount,
    error: undefined,
    cancel,
    goToWalletManualWithdraw,
  };
  if (!foundBalance) {
    return {
      status: "no-balance-for-currency",
      balance: undefined,
      payStatus,
      ...baseResult,
    };
  }
  const foundAmount = Amounts.parseOrThrow(foundBalance.available);
  if (payStatus.status === PreparePayResultType.InsufficientBalance) {
    return {
      status: "no-enough-balance",
      balance: foundAmount,
      payStatus,
      ...baseResult,
    };
  }
  if (payStatus.status === PreparePayResultType.AlreadyConfirmed) {
    return {
      status: "confirmed",
      balance: foundAmount,
      payStatus,
      ...baseResult,
    };
  }
  async function doPayment(): Promise {
    // if (payStatus.status !== "payment-possible") {
    //   throw TalerError.fromUncheckedDetail({
    //     code: TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR,
    //     when: new Date().toISOString(),
    //     hint: `payment is not possible: ${payStatus.status}`,
    //   });
    // }
    const res = await api.wallet.call(WalletApiOperation.ConfirmPay, {
      proposalId: payStatus.proposalId,
    });
    // handle confirm pay
    if (res.type !== ConfirmPayResultType.Done) {
      // throw new BackgroundError("Could not confirm payment", res.lastError)
      // // throw TalerError.fromUncheckedDetail({
      // //   code: TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR,
      // //   when: new Date().toISOString(),
      // //   hint: `could not confirm payment`,
      // //   payResult: res,
      // // });
      onSuccess(res.transactionId);
      return;
    }
    const fu = res.contractTerms.fulfillment_url;
    if (fu) {
      if (typeof window !== "undefined") {
        document.location.href = fu;
      } else {
        console.log(`should d to ${fu}`);
      }
    }
    onSuccess(res.transactionId);
  }
  const payHandler: ButtonHandler = {
    onClick: pushAlertOnError(doPayment),
  };
  // (payStatus.status === PreparePayResultType.PaymentPossible)
  return {
    status: "ready",
    payHandler,
    payStatus,
    ...baseResult,
    balance: foundAmount,
  };
}