/*
 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: unsortedAccounts,
}: BankDetailsProps): VNode {
  const { i18n } = useTranslationContext();
  const [index, setIndex] = useState(0);

  if (!unsortedAccounts.length) {
    return <div>the exchange account list is empty</div>;
  }

  const accounts = unsortedAccounts.sort((a, b) => {
    return (b.priority ?? 0) - (a.priority ?? 0);
  });

  const selectedAccount = accounts[index];
  const altCurrency = selectedAccount.currencySpecification?.name;

  const payto = parsePaytoUri(selectedAccount.paytoUri);

  if (!payto) return <Fragment />;
  payto.params["amount"] = 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>
          <div></div>
        </div>

        {children}

        {accounts.length > 1 ? (
          <Fragment>
            {accounts.map((ac, acIdx) => {
              const accountLabel = ac.bankLabel ?? `Account #${acIdx + 1}`;
              return (
                <Button
                  key={acIdx}
                  variant={acIdx === index ? "contained" : "outlined"}
                  onClick={async () => {
                    setIndex(acIdx);
                  }}
                >
                  {accountLabel} (
                  {ac.currencySpecification?.name ?? amount.currency})
                </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 ? (
    <Fragment>
      <Row name={i18n.str`Account`} value={payto.targetPath} />
    </Fragment>
  ) : 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-name"] || payto.params["receiver"] || undefined;
  return (
    <Frame title={i18n.str`Bank transfer details`}>
      <table>
        <tbody>
          <tr>
            <td colSpan={3}>
              <i18n.Translate>Step 1:</i18n.Translate>
              &nbsp;
              <i18n.Translate>
                Copy this code and paste it into the subject/purpose field in
                your banking app or bank website
              </i18n.Translate>
            </td>
          </tr>
          <Row name={i18n.str`Subject`} value={subject} literal />

          <tr>
            <td colSpan={3}>
              <i18n.Translate>Step 2:</i18n.Translate>
              &nbsp;
              <i18n.Translate>
                If you don't already have it in your banking favourites list,
                then copy and paste this IBAN and the name into the receiver
                fields in your banking app or website
              </i18n.Translate>
            </td>
          </tr>
          {accountPart}
          {receiver ? (
            <Row name={i18n.str`Receiver name`} value={receiver} />
          ) : undefined}

          <tr>
            <td colSpan={3}>
              <i18n.Translate>Step 3:</i18n.Translate>
              &nbsp;
              <i18n.Translate>
                Finish the wire transfer setting the amount in your banking app
                or website, then this withdrawal will proceed automatically.
              </i18n.Translate>
            </td>
          </tr>
          <Row
            name={i18n.str`Amount`}
            value={
              <Amount
                value={altCurrency ? selectedAccount.transferAmount! : amount}
                hideCurrency
              />
            }
          />

          <tr>
            <td colSpan={3}>
              <WarningBox style={{ margin: 0 }}>
                <span>
                  <i18n.Translate>
                    Make sure ALL data is correct, including the subject;
                    otherwise, the money will not arrive in this wallet. You can
                    use the copy buttons (<CopyIcon />) to prevent typing errors
                    or the "payto://" URI below to copy just one value.
                  </i18n.Translate>
                </span>
              </WarningBox>
            </td>
          </tr>

          <tr>
            <td colSpan={2} width="100%" style={{ wordBreak: "break-all" }}>
              <i18n.Translate>
                Alternative if your bank already supports PayTo URI, you can use
                this{" "}
                <a
                  target="_bank"
                  rel="noreferrer"
                  title="RFC 8905 for designating targets for payments"
                  href="https://tools.ietf.org/html/rfc8905"
                >
                  PayTo URI
                </a>{" "}
                link instead
              </i18n.Translate>
            </td>
            <td>
              <CopyButton getContent={() => stringifyPaytoUri(payto)} />
            </td>
          </tr>
        </tbody>
      </table>
    </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>
  );
}
