/*
 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,
  parsePaytoUri,
  segwitMinAmount,
  stringifyPaytoUri,
  TranslatedString,
  WithdrawalExchangeAccountDetails
} from "@gnu-taler/taler-util";
import {
  useTranslationContext
} from "@gnu-taler/web-util/browser";
import { ComponentChildren, Fragment, h, VNode } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
import { CopiedIcon, CopyIcon } from "../svg/index.js";
import { Amount } from "./Amount.js";
import { ButtonBox, TooltipLeft, WarningBox } from "./styled/index.js";
import { Button } from "../mui/Button.js";

export interface BankDetailsProps {
  subject: string;
  amount: AmountJson;
  accounts: WithdrawalExchangeAccountDetails[],
}

export function BankDetailsByPaytoType({
  subject,
  amount,
  accounts,
}: BankDetailsProps): VNode {
  const { i18n } = useTranslationContext();
  const [index, setIndex] = useState(0)
  const [currency, setCurrency] = useState(amount.currency)
  if (!accounts.length) {
    return <div>the exchange account list is empty</div>
  }
  const selectedAccount = accounts[index];
  const altCurrency = selectedAccount.currencySpecification?.name

  const payto = parsePaytoUri(selectedAccount.paytoUri);

  if (!payto) return <Fragment />;
  payto.params["amount"] = currency === altCurrency ? selectedAccount.transferAmount! :Amounts.stringify(amount) ;
  payto.params["message"] = subject;


  function Frame({ title, children }: { title: TranslatedString, children: ComponentChildren }): VNode {
    return <section
      style={{
        textAlign: "left",
        border: "solid 1px black",
        padding: 8,
        borderRadius: 4,
      }}
    >
      <div style={{ display: "flex", width: "100%", justifyContent: "space-between" }}>
        <p style={{ marginTop: 0 }}>
          {title}
        </p>
        {accounts.length > 1 ?
          <Button variant="contained"
            onClick={async () => {
              setIndex((index + 1) % accounts.length)
            }}
          >
            <i18n.Translate>Next</i18n.Translate>
          </Button>
          : undefined}
      </div>

      {children}

      {altCurrency ?
        <Fragment>
          <Button variant={currency === amount.currency ? "contained" : "outlined"}
            onClick={async () => {
              setCurrency(amount.currency)
            }}
          >
            <i18n.Translate>{amount.currency}</i18n.Translate>
          </Button>
          <Button variant={currency === altCurrency ? "contained" : "outlined"}
            onClick={async () => {
              setCurrency(altCurrency)
            }}
          >
            <i18n.Translate>{altCurrency}</i18n.Translate>
          </Button>
        </Fragment>
        : undefined}
    </section>
  }

  if (payto.isKnown && payto.targetType === "bitcoin") {
    const min = segwitMinAmount(amount.currency);
    const addrs = payto.segwitAddrs.map(
      (a) => `${a} ${Amounts.stringifyValue(min)}`,
    );
    addrs.unshift(`${payto.targetPath} ${Amounts.stringifyValue(amount)}`);
    const copyContent = addrs.join("\n");
    return (
      <Frame title={i18n.str`Bitcoin transfer details`}>
        <p>
          <i18n.Translate>
            The exchange need a transaction with 3 output, one output is the
            exchange account and the other two are segwit fake address for
            metadata with an minimum amount.
          </i18n.Translate>
        </p>

        <p>
          <i18n.Translate>
            In bitcoincore wallet use &apos;Add Recipient&apos; button to add
            two additional recipient and copy addresses and amounts
          </i18n.Translate>
        </p>
        <table>
          <tr>
            <td>
              <div>
                {payto.targetPath} <Amount value={amount} hideCurrency /> BTC
              </div>
              {payto.segwitAddrs.map((addr, i) => (
                <div key={i}>
                  {addr} <Amount value={min} hideCurrency /> BTC
                </div>
              ))}
            </td>
            <td></td>
            <td>
              <CopyButton getContent={() => copyContent} />
            </td>
          </tr>
        </table>
        <p>
          <i18n.Translate>
            Make sure the amount show{" "}
            {Amounts.stringifyValue(Amounts.sum([amount, min, min]).amount)}{" "}
            BTC, else you have to change the base unit to BTC
          </i18n.Translate>
        </p>
      </Frame>
    );
  }

  const accountPart = !payto.isKnown ? (
    <Row name={i18n.str`Account`} value={payto.targetPath} />
  ) : payto.targetType === "x-taler-bank" ? (
    <Fragment>
      <Row name={i18n.str`Bank host`} value={payto.host} />
      <Row name={i18n.str`Bank account`} value={payto.account} />
    </Fragment>
  ) : payto.targetType === "iban" ? (
    <Fragment>
      {payto.bic !== undefined ? (
        <Row name={i18n.str`BIC`} value={payto.bic} />
      ) : undefined}
      <Row name={i18n.str`IBAN`} value={payto.iban} />
    </Fragment>
  ) : undefined;

  const receiver = payto.params["receiver"] || undefined;
  return (
    <Frame title={i18n.str`Bank transfer details`}>
      <table>
        {accountPart}
        {currency === altCurrency ? <Fragment>
          <Row
            name={i18n.str`Amount`}
            value={<Amount value={selectedAccount.transferAmount!} />}
          />
          <Row
            name={i18n.str`Converted`}
            value={<Amount value={amount} />}
          />

        </Fragment> :
          <Row
            name={i18n.str`Amount`}
            value={<Amount value={amount} />}
          />
        }
        <Row name={i18n.str`Subject`} value={subject} literal />
        {receiver ? (
          <Row name={i18n.str`Receiver name`} value={receiver} />
        ) : undefined}
      </table>
      <table>
        <tbody>
          <tr>
            <td>
              <pre>
                <b>
                  <a
                    target="_bank"
                    rel="noreferrer"
                    title="RFC 8905 for designating targets for payments"
                    href="https://tools.ietf.org/html/rfc8905"
                  >
                    Payto URI
                  </a>
                </b>
              </pre>
            </td>
            <td width="100%" style={{ wordBreak: "break-all" }}>
              {stringifyPaytoUri(payto)}
            </td>
            <td>
              <CopyButton getContent={() => stringifyPaytoUri(payto)} />
            </td>
          </tr>
        </tbody>
      </table>
      <p>
        <WarningBox>
          <i18n.Translate>
            Make sure to use the correct subject, otherwise the money will not
            arrive in this wallet.
          </i18n.Translate>
        </WarningBox>
      </p>
    </Frame>
  );
}

function CopyButton({ getContent }: { getContent: () => string }): VNode {
  const [copied, setCopied] = useState(false);
  function copyText(): void {
    navigator.clipboard.writeText(getContent() || "");
    setCopied(true);
  }
  useEffect(() => {
    if (copied) {
      setTimeout(() => {
        setCopied(false);
      }, 1000);
    }
  }, [copied]);

  if (!copied) {
    return (
      <ButtonBox onClick={copyText}>
        <CopyIcon />
      </ButtonBox>
    );
  }
  return (
    <TooltipLeft content="Copied">
      <ButtonBox disabled>
        <CopiedIcon />
      </ButtonBox>
    </TooltipLeft>
  );
}

function Row({
  name,
  value,
  literal,
}: {
  name: TranslatedString;
  value: string | VNode;
  literal?: boolean;
}): VNode {
  const preRef = useRef<HTMLPreElement>(null);
  const tdRef = useRef<HTMLTableCellElement>(null);

  function getContent(): string {
    return preRef.current?.textContent || tdRef.current?.textContent || "";
  }

  return (
    <tr>
      <td style={{ paddingRight: 8 }}>
        <b>{name}</b>
      </td>
      {literal ? (
        <td>
          <pre
            ref={preRef}
            style={{ whiteSpace: "pre-wrap", wordBreak: "break-word" }}
          >
            {value}
          </pre>
        </td>
      ) : (
        <td ref={tdRef}>{value}</td>
      )}
      <td>
        <CopyButton getContent={getContent} />
      </td>
    </tr>
  );
}
