/*
 This file is part of GNU Taler
 (C) 2022-2025 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 {
  Amounts,
  InsufficientBalanceHint,
  TranslatedString,
  assertUnreachable,
  parsePayUri
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { useBackendContext } from "../context/backend.js";
import { PaymentStates } from "../cta/Payment/views.js";
import { Button } from "../mui/Button.js";
import { Amount } from "./Amount.js";
import { Part } from "./Part.js";
import { QR } from "./QR.js";
import { LinkSuccess, WarningBox } from "./styled/index.js";

export function PaymentButtons({ paymentState: state }: { paymentState: PaymentStates }): VNode {
  const { i18n } = useTranslationContext();

  switch (state.status) {
    case "ready": {
      return (
        <Fragment>
          <section>
            <Button
              variant="contained"
              color="success"
              onClick={state.payHandler?.onClick}
            >
              <i18n.Translate>
                Pay &nbsp;
                {<Amount value={state.amount} />}
              </i18n.Translate>
            </Button>
          </section>
          <PayWithMobile uri={state.shareUri} />
        </Fragment>
      );
    }

    case "confirmed": {
      return (
        <Fragment>
          <section>
            {state.message && (
              <Part
                title={i18n.str`Merchant message`}
                text={state.message as TranslatedString}
                kind="neutral"
              />
            )}
          </section>
        </Fragment>
      );
    }

    case "no-enough-balance": {
      let BalanceMessage = "";
      const { balanceDetails, amount } = state
      if (!balanceDetails) {
          BalanceMessage = i18n.str`Balance is not enough.`;
      } else switch (balanceDetails.causeHint) {
        case InsufficientBalanceHint.MerchantAcceptInsufficient: {
          BalanceMessage = i18n.str`Balance is not enough because merchant will just accept ${Amounts.stringifyValue(
            balanceDetails.balanceReceiverAcceptable,
          )} ${amount.currency
            }. To know more you can check which exchange and auditors the merchant trust.`;
          break;
        }
        case InsufficientBalanceHint.MerchantDepositInsufficient: {
          BalanceMessage = i18n.str`Balance is not enough because merchant will just accept ${Amounts.stringifyValue(
            balanceDetails.balanceReceiverDepositable,
          )} ${amount.currency
            }. To know more you can check which wire methods the merchant accepts.`;
          break;
        }
        case InsufficientBalanceHint.AgeRestricted: {
          BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue(
            balanceDetails.balanceAgeAcceptable,
          )} ${amount.currency} to pay for this contract which is restricted.`;
          break;
        }
        case InsufficientBalanceHint.WalletBalanceMaterialInsufficient: {
          BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue(
            balanceDetails.balanceMaterial,
          )} ${amount.currency
            } to spend right know. There are some coins that need to be refreshed.`;
          break;
        }
        case InsufficientBalanceHint.WalletBalanceAvailableInsufficient: {
          BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue(
            balanceDetails.balanceAvailable,
          )} ${amount.currency} available.`;
          break;
        }
        case InsufficientBalanceHint.ExchangeMissingGlobalFees: {
          BalanceMessage = i18n.str`Provider is missing the global fee configuration, this likely means it is misconfigured.`;
          break;
        }
        case InsufficientBalanceHint.FeesNotCovered: {
          BalanceMessage = i18n.str`Balance looks like it should be enough, but doesn't cover all fees requested by the merchant and payment processor. Please ensure there is at least ${Amounts.stringifyValue(
            Amounts.stringify(
              Amounts.sub(
                amount,
                balanceDetails.maxEffectiveSpendAmount,
              ).amount,
            ),
          )} ${amount.currency
            } more balance in your wallet or ask your merchant to cover more of the fees.`;
          break;
        }
        case undefined: {
          BalanceMessage = i18n.str`Balance is not enough.`;
          break;
        }
        default:
          assertUnreachable(balanceDetails.causeHint);
      }

      return (
        <Fragment>
          <section>
            <WarningBox>{BalanceMessage}</WarningBox>
          </section>
          <section>
            <Button
              variant="contained"
              color="success"
              onClick={() => state.goToWalletManualWithdraw(Amounts.stringify(amount))}
            >
              <i18n.Translate>Get digital cash</i18n.Translate>
            </Button>
          </section>
          <PayWithMobile uri={state.shareUri} />
        </Fragment>
      );
    }
    default: {
      assertUnreachable(state);
    }
  }
}

function PayWithMobile({ uri }: { uri: string }): VNode {
  const { i18n } = useTranslationContext();
  const api = useBackendContext();

  const payUri = parsePayUri(uri);

  const [showQR, setShowQR] = useState<string | undefined>(undefined);
  async function sharePrivatePaymentURI() {
    if (!payUri) {
      return;
    }
    if (!showQR) {
      const result = await api.wallet.call(WalletApiOperation.SharePayment, {
        merchantBaseUrl: payUri.merchantBaseUrl,
        orderId: payUri.orderId,
      });
      setShowQR(result.privatePayUri);
    } else {
      setShowQR(undefined);
    }
  }
  if (!payUri) {
    return <Fragment />;
  }
  return (
    <section>
      <LinkSuccess upperCased onClick={sharePrivatePaymentURI}>
        {!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`}
      </LinkSuccess>
      {showQR && (
        <div>
          <QR text={showQR} />
          <i18n.Translate>
            Scan the QR code or &nbsp;
            <a href={showQR}>
              <i18n.Translate>click here</i18n.Translate>
            </a>
          </i18n.Translate>
        </div>
      )}
    </section>
  );
}
