/*
 This file is part of GNU Taler
 (C) 2021-2024 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/>
 */

/**
 *
 * @author Sebastian Javier Marchano (sebasjm)
 */

import {
  AbsoluteTime,
  AmountJson,
  Amounts,
  HostPortPath,
  MerchantContractVersion,
  Result,
  TalerMerchantApi,
  TalerUris,
  TransactionWireTransfer,
  assertUnreachable,
  stringifyRefundUri,
} from "@gnu-taler/taler-util";
import {
  NotificationCardBulma,
  RenderAmountBulma,
  useTranslationContext
} from "@gnu-taler/web-util/browser";
import { format, formatDistance } from "date-fns";
import { Fragment, VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
import { QR_Taler } from "../../../../components/exception/QR.js";
import { FormProvider } from "../../../../components/form/FormProvider.js";
import { Input } from "../../../../components/form/Input.js";
import { InputCurrency } from "../../../../components/form/InputCurrency.js";
import { InputDate } from "../../../../components/form/InputDate.js";
import { InputDurationDropdown } from "../../../../components/form/InputDurationDropdown.js";
import { InputGroup } from "../../../../components/form/InputGroup.js";
import { InputLocation } from "../../../../components/form/InputLocation.js";
import { TextField } from "../../../../components/form/TextField.js";
import { ConfirmModal } from "../../../../components/modal/index.js";
import { ProductList } from "../../../../components/product/ProductList.js";
import { Tooltip } from "../../../../components/Tooltip.js";
import { useSessionContext } from "../../../../context/session.js";
import {
  datetimeFormatForPreferences,
  usePreference,
} from "../../../../hooks/preference.js";
import { mergeRefunds } from "../../../../utils/amount.js";
import { RefundModal } from "../list/Table.js";
import { Event, Timeline } from "./Timeline.js";

const TALER_SCREEN_ID = 44;

type Entity = TalerMerchantApi.MerchantOrderStatusResponse;
type CT = TalerMerchantApi.MerchantContractTerms;
type CT0 = TalerMerchantApi.MerchantContractTermsV0;
type CT1 = TalerMerchantApi.MerchantContractTermsV1;

export interface Props {
  onBack: () => void;
  selected: Entity;
  id: string;
  onRefunded: () => void;
  onSelectWireTransfer: (id: number) => void;
}

type Paid = TalerMerchantApi.CheckPaymentPaidResponse & {
  refund_taken: string;
};
type Unpaid = TalerMerchantApi.CheckPaymentUnpaidResponse;
type Claimed = TalerMerchantApi.CheckPaymentClaimedResponse;

function ContractTerms({ value }: { value: CT }) {
  if (value.version === undefined) {
    return <ContractTerms_V0 value={value} />;
  }
  switch (value.version) {
    case MerchantContractVersion.V0:
      return <ContractTerms_V0 value={value} />;
    case MerchantContractVersion.V1:
      return <ContractTerms_V1 value={value} />;
    default:
      assertUnreachable(value.version);
  }
}

function ContractTerms_V0({ value }: { value: CT0 }) {
  const { i18n } = useTranslationContext();

  return (
    <InputGroup name="contract_terms" label={i18n.str`Contract terms`}>
      <FormProvider<CT0> object={value}>
        <Input<CT0>
          readonly
          name="summary"
          label={i18n.str`Summary`}
          tooltip={i18n.str`Human-readable description of the whole purchase`}
        />
        <InputCurrency<CT0>
          readonly
          name="amount"
          label={i18n.str`Amount`}
          tooltip={i18n.str`Total price for the transaction`}
        />
        {value.fulfillment_url && (
          <Input<CT0>
            readonly
            name="fulfillment_url"
            label={i18n.str`Fulfillment URL`}
            tooltip={i18n.str`URL for this purchase`}
          />
        )}
        <InputCurrency<CT0>
          readonly
          name="max_fee"
          label={i18n.str`Max fee`}
          tooltip={i18n.str`Maximum total deposit fee accepted by the merchant for this contract`}
        />
        <InputDate<CT0>
          readonly
          name="timestamp"
          label={i18n.str`Created at`}
          tooltip={i18n.str`Time when this contract was generated`}
        />
        <InputDate<CT0>
          readonly
          name="pay_deadline"
          label={i18n.str`Payment deadline`}
          tooltip={i18n.str`After this deadline, the merchant won't accept payments for the contract`}
        />
        <InputDate<CT0>
          readonly
          name="refund_deadline"
          label={i18n.str`Refund deadline`}
          tooltip={i18n.str`After this deadline has passed, no refunds will be accepted.`}
        />
        <InputDate<CT0>
          readonly
          name="wire_transfer_deadline"
          label={i18n.str`Wire transfer deadline`}
          tooltip={i18n.str`Transfer deadline for the exchange`}
        />
        <InputDurationDropdown<CT0>
          readonly
          name="auto_refund"
          label={i18n.str`Auto-refund delay`}
          tooltip={i18n.str`How long the wallet should try to get an automatic refund for the purchase`}
        />
        <InputDate<CT0>
          readonly
          name="delivery_date"
          label={i18n.str`Delivery date`}
          tooltip={i18n.str`Time indicating when the order should be delivered`}
        />
        <InputGroup
          name="delivery_location"
          label={i18n.str`Delivery location`}
          tooltip={i18n.str`Where the order will be delivered`}
        >
          <InputLocation name="delivery_location" />
        </InputGroup>
        <Input<CT0>
          readonly
          name="extra"
          label={i18n.str`Extra info`}
          tooltip={i18n.str`Extra data that is only interpreted by the merchant frontend`}
        />
      </FormProvider>
    </InputGroup>
  );
}

function ContractTerms_V1({ value }: { value: CT1 }) {
  const { i18n } = useTranslationContext();

  return (
    <InputGroup name="contract_terms" label={i18n.str`Contract terms`}>
      <FormProvider<CT1> object={value}>
        <Input<CT1>
          readonly
          name="summary"
          label={i18n.str`Summary`}
          tooltip={i18n.str`Human-readable description of the whole purchase`}
        />
        {/* <InputCurrency<CT1>
          readonly
          name="amount"
          label={i18n.str`Amount`}
          tooltip={i18n.str`Total price for the transaction`}
        />
        <Input<CT1>
          readonly
          name="max_fee"
          label={i18n.str`Max fee`}
          tooltip={i18n.str`Maximum total deposit fee accepted by the merchant for this contract`}
        /> */}
        {value.fulfillment_url && (
          <Input<CT1>
            readonly
            name="fulfillment_url"
            label={i18n.str`Fulfillment URL`}
            tooltip={i18n.str`URL for this purchase`}
          />
        )}
        <InputDate<CT1>
          readonly
          name="timestamp"
          label={i18n.str`Created at`}
          tooltip={i18n.str`Time when this contract was generated`}
        />
        <InputDate<CT1>
          readonly
          name="pay_deadline"
          label={i18n.str`Payment deadline`}
          tooltip={i18n.str`After this deadline, the merchant won't accept payments for the contract`}
        />
        <InputDate<CT1>
          readonly
          name="refund_deadline"
          label={i18n.str`Refund deadline`}
          tooltip={i18n.str`After this deadline has passed, no refunds will be accepted.`}
        />
        <InputDate<CT1>
          readonly
          name="wire_transfer_deadline"
          label={i18n.str`Wire transfer deadline`}
          tooltip={i18n.str`Transfer deadline for the exchange`}
        />
        <InputDate<CT1>
          readonly
          name="delivery_date"
          label={i18n.str`Delivery date`}
          tooltip={i18n.str`Time indicating when the order should be delivered`}
        />
        <InputGroup
          name="delivery_location"
          label={i18n.str`Delivery location`}
          tooltip={i18n.str`Where the order will be delivered`}
        >
          <InputLocation name="delivery_location" />
        </InputGroup>
        <InputDurationDropdown<CT1>
          readonly
          name="auto_refund"
          label={i18n.str`Auto-refund delay`}
          tooltip={i18n.str`How long the wallet should try to get an automatic refund for the purchase`}
        />
        <Input<CT1>
          readonly
          name="extra"
          label={i18n.str`Extra info`}
          tooltip={i18n.str`Extra data that is only interpreted by the merchant frontend`}
        />
      </FormProvider>
    </InputGroup>
  );
}

function ClaimedPage({
  id,
  order,
}: {
  id: string;
  order: TalerMerchantApi.CheckPaymentClaimedResponse;
}) {
  const { i18n } = useTranslationContext();
  const [value, valueHandler] = useState<Partial<Claimed>>(order);
  const [preferences] = usePreference();
  // useWaitForOrderPayment(id, order);
  const now = new Date();
  const refundable =
    order.contract_terms.refund_deadline.t_s !== "never" &&
    now.getTime() < order.contract_terms.refund_deadline.t_s * 1000;
  const events: Event[] = [];
  if (order.contract_terms.timestamp.t_s !== "never") {
    events.push({
      when: new Date(order.contract_terms.timestamp.t_s * 1000),
      description: i18n.str`order created`,
      type: "start",
    });
  }
  if (order.contract_terms.pay_deadline.t_s !== "never") {
    events.push({
      when: new Date(order.contract_terms.pay_deadline.t_s * 1000),
      description: i18n.str`pay deadline`,
      type: "pay-deadline",
    });
  }
  if (order.contract_terms.refund_deadline.t_s !== "never" && refundable) {
    events.push({
      when: new Date(order.contract_terms.refund_deadline.t_s * 1000),
      description: i18n.str`refund deadline`,
      type: "refund-deadline",
    });
  }
  if (
    order.contract_terms.delivery_date &&
    order.contract_terms.delivery_date.t_s !== "never"
  ) {
    events.push({
      when: new Date(order.contract_terms.delivery_date?.t_s * 1000),
      description: i18n.str`delivery`,
      type: "delivery",
    });
  }

  return (
    <div>
      <section class="section">
        <div class="columns">
          <div class="column" />
          <div class="column is-10">
            <section class="hero is-hero-bar">
              <div class="hero-body">
                <div class="level">
                  <div class="level-left">
                    <div class="level-item">
                      <i18n.Translate>Order</i18n.Translate> #{id}
                      <div class="tag is-info ml-4">
                        <i18n.Translate>Claimed</i18n.Translate>
                      </div>
                    </div>
                  </div>
                </div>

                {/* {order.contract_terms.version} */}
                {/* <div class="level">
                  <div class="level-left">
                    <div class="level-item">
                      <h1 class="title">{order.contract_terms.amount}</h1>
                    </div>
                  </div>
                </div> */}

                <div class="level">
                  <div class="level-left" style={{ maxWidth: "100%" }}>
                    <div class="level-item" style={{ maxWidth: "100%" }}>
                      <div
                        class="content"
                        style={{
                          whiteSpace: "nowrap",
                          overflow: "hidden",
                          textOverflow: "ellipsis",
                        }}
                      >
                        <p>
                          <b>
                            <i18n.Translate>Claimed at</i18n.Translate>:
                          </b>{" "}
                          {order.contract_terms.timestamp.t_s === "never"
                            ? i18n.str`Never`
                            : format(
                                new Date(
                                  order.contract_terms.timestamp.t_s * 1000,
                                ),
                                datetimeFormatForPreferences(preferences),
                              )}
                        </p>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </section>

            <section class="section">
              <div class="columns">
                <div class="column is-4">
                  <div class="title">
                    <i18n.Translate>Timeline</i18n.Translate>
                  </div>
                  <Timeline events={events} />
                </div>
                <div class="column is-8">
                  <div class="title">
                    <i18n.Translate>Payment details</i18n.Translate>
                  </div>
                  <FormProvider<Claimed>
                    object={value}
                    valueHandler={valueHandler}
                  >
                    <Input
                      name="contract_terms.summary"
                      readonly
                      inputType="multiline"
                      label={i18n.str`Summary`}
                    />
                    <InputCurrency
                      name="contract_terms.amount"
                      readonly
                      label={i18n.str`Amount`}
                    />
                    <Input<Paid>
                      name="order_status"
                      readonly
                      label={i18n.str`Order status`}
                      toStr={(d) => {
                        switch (d) {
                          case "paid":
                            return i18n.str`Paid`;
                          case "claimed":
                            return i18n.str`Claimed`;
                          case "unpiad":
                            return i18n.str`Unpaid`;
                        }
                        return d;
                      }}
                    />
                  </FormProvider>
                </div>
              </div>
            </section>

            {order.contract_terms.products?.length ? (
              <Fragment>
                <div class="title">
                  <i18n.Translate>Product list</i18n.Translate>
                </div>
                <ProductList list={order.contract_terms.products} />
              </Fragment>
            ) : undefined}

            {!value.contract_terms ? undefined : (
              <ContractTerms value={value.contract_terms} />
            )}
          </div>
          <div class="column" />
        </div>
      </section>
    </div>
  );
}
function PaidPage({
  id,
  order,
  onRefund,
  onWireTransferSelection,
}: {
  id: string;
  order: TalerMerchantApi.CheckPaymentPaidResponse;
  onRefund: (id: string) => void;
  onWireTransferSelection: (id: number) => void;
}) {
  const { state, config } = useSessionContext();
  const [verifyingWiretransfer, setVerifyingWiretransfer] = useState<
    TransactionWireTransfer[]
  >([]);
  const totalRefundAlreadyTaken = order.refund_details.reduce((prev, cur) => {
    if (cur.pending) return prev;
    return Amounts.add(prev, Amounts.parseOrThrow(cur.amount)).amount;
  }, Amounts.zeroOfCurrency(config.currency));
  // value.refund_taken = Amounts.stringify(totalRefundAlreadyTaken);

  const [value, valueHandler] = useState<Partial<Paid>>({
    ...order,
    refund_taken: Amounts.stringify(totalRefundAlreadyTaken),
  });
  const { i18n } = useTranslationContext();

  const now = new Date();
  const merchantCanRefund =
    order.contract_terms.refund_deadline.t_s !== "never" &&
    now.getTime() < order.contract_terms.refund_deadline.t_s * 1000;

  const wireDeadlineInThePast =
    order.contract_terms.wire_transfer_deadline.t_s !== "never" &&
    order.contract_terms.wire_transfer_deadline.t_s * 1000 < now.getTime();
  const [_, reload] = useState(false);
  useEffect(() => {
    if (wireDeadlineInThePast) return;
    const deadline = order.contract_terms.wire_transfer_deadline;
    if (deadline.t_s === "never") return;
    const diff = deadline.t_s * 1000 - new Date().getTime();
    setTimeout(() => {
      reload(true);
    }, diff + 100);
  }, []);

  const events: Event[] = [];
  if (
    order.contract_terms.refund_deadline.t_s !== "never" &&
    merchantCanRefund
  ) {
    events.push({
      when: new Date(order.contract_terms.refund_deadline.t_s * 1000),
      description: i18n.str`refund deadline`,
      type: "refund-deadline",
    });
  }
  if (
    order.contract_terms.delivery_date &&
    order.contract_terms.delivery_date.t_s !== "never"
  ) {
    if (order.contract_terms.delivery_date)
      events.push({
        when: new Date(order.contract_terms.delivery_date?.t_s * 1000),
        description: i18n.str`delivery`,
        type: "delivery",
      });
  }

  const sortedOrders = [...order.refund_details].sort((a, b) =>
    AbsoluteTime.cmp(
      AbsoluteTime.fromProtocolTimestamp(a.timestamp),
      AbsoluteTime.fromProtocolTimestamp(b.timestamp),
    ),
  );

  const orderAmounts = getOrderAmountAndMaxDepositFee(order);
  if (orderAmounts === "v1-without-index") {
    return (
      <i18n.Translate>
        The contract terms have a v1 order without choices_index.
      </i18n.Translate>
    );
  }
  if (orderAmounts === "v1-wrong-index") {
    return (
      <i18n.Translate>
        The contract terms have a v1 order with a bad choices_index.
      </i18n.Translate>
    );
  }
  const { amount, maxDepositFee } = orderAmounts;

  let totalRefundedTaken = Amounts.zeroOfAmount(amount);
  sortedOrders.reduce(mergeRefunds, []).forEach((e) => {
    if (e.timestamp.t_s === "never") return;
    if (e.pending) {
      if (wireDeadlineInThePast) {
        events.push({
          when: new Date(e.timestamp.t_s * 1000),
          description: !e.reason ? (
            <i18n.Translate>
              refund missed:{" "}
              <RenderAmountBulma
                value={Amounts.parseOrThrow(e.amount)}
                specMap={config.currencies}
              />
            </i18n.Translate>
          ) : (
            <i18n.Translate>
              refund missed:{" "}
              <RenderAmountBulma
                value={Amounts.parseOrThrow(e.amount)}
                specMap={config.currencies}
              />
              : {e.reason}
            </i18n.Translate>
          ),
          type: "refund-missed",
        });
      } else {
        events.push({
          when: new Date(e.timestamp.t_s * 1000),
          description: !e.reason ? (
            <i18n.Translate>
              refund created:{" "}
              <RenderAmountBulma
                value={Amounts.parseOrThrow(e.amount)}
                specMap={config.currencies}
              />
            </i18n.Translate>
          ) : (
            <i18n.Translate>
              refund created:{" "}
              <RenderAmountBulma
                value={Amounts.parseOrThrow(e.amount)}
                specMap={config.currencies}
              />
              : {e.reason}
            </i18n.Translate>
          ),
          type: "refund-created",
        });
      }
    } else {
      totalRefundedTaken = Amounts.add(totalRefundedTaken, e.amount).amount;
      events.push({
        when: new Date(e.timestamp.t_s * 1000),
        description: !e.reason ? (
          <i18n.Translate>
            refund taken:{" "}
            <RenderAmountBulma
              value={Amounts.parseOrThrow(e.amount)}
              specMap={config.currencies}
            />
          </i18n.Translate>
        ) : (
          <i18n.Translate>
            refund taken:{" "}
            <RenderAmountBulma
              value={Amounts.parseOrThrow(e.amount)}
              specMap={config.currencies}
            />
            : {e.reason}
          </i18n.Translate>
        ),
        type: "refund-taken",
      });
    }
  });

  const wireMap: Record<
    string,
    {
      time: number;
      amount: AmountJson;
      confirmed: boolean;
    }
  > = {};

  const unconfirmedWireTransfers: TransactionWireTransfer[] = [];
  let totalFromWireTransfer = Amounts.zeroOfAmount(amount);
  if (order.wire_details.length) {
    order.wire_details.forEach((w) => {
      totalFromWireTransfer = Amounts.add(
        totalFromWireTransfer,
        w.amount,
        w.deposit_fee,
      ).amount;

      // fill up and merge wireMap by wire id
      if (!wireMap[w.wtid]) {
        const info = {
          time:
            w.execution_time.t_s === "never" ? 0 : w.execution_time.t_s * 1000,
          amount: Amounts.parseOrThrow(w.amount),
          confirmed: w.confirmed,
        };
        wireMap[w.wtid] = info;
      } else {
        const info = {
          time: wireMap[w.wtid].time, // keep the first time
          confirmed: wireMap[w.wtid].confirmed && w.confirmed, // both should be confirmed
          amount: Amounts.add(
            Amounts.parseOrThrow(w.amount),
            wireMap[w.wtid].amount,
          ).amount,
        };
        wireMap[w.wtid] = info;
      }
      if (!w.confirmed) {
        unconfirmedWireTransfers.push(w);
      }
    });
    Object.values(wireMap).forEach((info) => {
      events.push({
        when: new Date(info.time),
        description: (
          <i18n.Translate>
            wired{" "}
            <RenderAmountBulma
              value={info.amount}
              specMap={config.currencies}
            />
          </i18n.Translate>
        ),
        type: info.confirmed ? "wired-confirmed" : "wired-pending",
      });
    });
  }
  const maxTotalFee = Amounts.add(totalRefundedTaken, maxDepositFee).amount;
  const shouldBeWiredMinimum = Amounts.sub(amount, maxTotalFee).amount;
  // we have a minimum but not a price value
  // because deposit fee depends on customer coins
  const notAllHasBeenWired =
    Amounts.cmp(totalFromWireTransfer, shouldBeWiredMinimum) < 0;
  const w_deadline = AbsoluteTime.fromProtocolTimestamp(
    order.contract_terms.wire_transfer_deadline,
  );
  if (w_deadline.t_ms !== "never") {
    if (!AbsoluteTime.isExpired(w_deadline)) {
      events.push({
        when: new Date(w_deadline.t_ms),
        description: i18n.str`wire deadline`,
        type: "wire-deadline",
      });
    } else {
      if (notAllHasBeenWired) {
        events.push({
          when: new Date(w_deadline.t_ms),
          description: i18n.str`wire deadline`,
          type: "wired-overdue",
        });
      }
    }
  }

  events.sort((a, b) => {
    return b.when.getTime() - a.when.getTime();
  });

  const nextEvent = events.find((e) => {
    return e.when.getTime() > now.getTime();
  });

  const refundURI =
    !order.refunded || wireDeadlineInThePast
      ? undefined
      : stringifyRefundUri({
          merchantBaseUrl: state.backendUrl.href as HostPortPath,
          orderId: order.contract_terms.order_id,
        });

  return (
    <div>
      <section class="section">
        <ConfirmModal
          label={i18n.str`OK`}
          description={i18n.str`Related wire transfers`}
          active={verifyingWiretransfer.length > 0}
          onCancel={() => {
            setVerifyingWiretransfer([]);
          }}
          // onConfirm={onConfirm}
        >
          <CardTableIncoming
            transfers={verifyingWiretransfer}
            onSelected={onWireTransferSelection}
          />
        </ConfirmModal>
        {/* )} */}
        <div class="columns">
          <div class="column" />
          <div class="column is-10">
            <section class="hero is-hero-bar">
              <div class="hero-body">
                <div class="level">
                  <div class="level-left">
                    <div class="level-item">
                      <i18n.Translate>Order</i18n.Translate> #{id}
                      <div class="tag is-success ml-4">
                        <i18n.Translate>Paid</i18n.Translate>
                      </div>
                      {order.wired ? (
                        unconfirmedWireTransfers.length > 0 ? (
                          <div class="tag is-warning ml-4">
                            <i18n.Translate>Unconfirmed</i18n.Translate>
                          </div>
                        ) : (
                          <div class="tag is-info ml-4">
                            <i18n.Translate>Confirmed</i18n.Translate>
                          </div>
                        )
                      ) : null}
                      {order.refunded ? (
                        <div class="tag is-danger ml-4">
                          <i18n.Translate>Refunded</i18n.Translate>
                        </div>
                      ) : null}
                    </div>
                  </div>
                </div>
                <div class="level">
                  <div class="level-left">
                    <div class="level-item">
                      <h1 class="title">
                        <RenderAmountBulma
                          value={amount}
                          specMap={config.currencies}
                        />
                      </h1>
                    </div>
                  </div>
                  <div class="level-right">
                    <div class="level-item">
                      <h1 class="title">
                        <div class="buttons">
                          <Tooltip
                            text={
                              merchantCanRefund
                                ? i18n.str`Refund order`
                                : i18n.str`Not refundable`
                            }
                          >
                            <button
                              type="button"
                              class="button is-danger"
                              disabled={!merchantCanRefund}
                              onClick={() => onRefund(id)}
                            >
                              <i18n.Translate>Refund</i18n.Translate>
                            </button>
                          </Tooltip>
                          <Tooltip
                            text={
                              !order.wire_details.length
                                ? i18n.str`No wire transfer reported`
                                : i18n.str`Check wire transfers`
                            }
                          >
                            <button
                              type="button"
                              class="button"
                              style={{ marginLeft: 5 }}
                              disabled={!order.wire_details.length}
                              onClick={() => {
                                setVerifyingWiretransfer(order.wire_details);
                              }}
                            >
                              <i18n.Translate>Wire transfers</i18n.Translate>
                            </button>
                          </Tooltip>
                        </div>
                      </h1>
                    </div>
                  </div>
                </div>

                <div class="level">
                  <div class="level-left" style={{ maxWidth: "100%" }}>
                    <div class="level-item" style={{ maxWidth: "100%" }}>
                      <div
                        class="content"
                        style={{
                          whiteSpace: "nowrap",
                          overflow: "hidden",
                          textOverflow: "ellipsis",
                        }}
                      >
                        {nextEvent && (
                          <p>
                            <i18n.Translate>Next event in </i18n.Translate>{" "}
                            {formatDistance(
                              nextEvent.when,
                              new Date(),
                              // "yyyy/MM/dd HH:mm:ss",
                            )}
                          </p>
                        )}
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </section>

            {unconfirmedWireTransfers.length === 0 ? undefined : (
              <NotificationCardBulma
                notification={{
                  type: "INFO",
                  message: i18n.str`The order was wired.`,
                  description: (
                    <div>
                      <p>
                        <i18n.Translate>
                          Bank processing can take a few business days,
                          depending on your bank.
                        </i18n.Translate>
                      </p>
                    </div>
                  ),
                }}
              />
            )}

            <section class="section">
              <div class="columns">
                <div class="column is-4">
                  <div class="title">
                    <i18n.Translate>Timeline</i18n.Translate>
                  </div>
                  <Timeline events={events} />
                </div>
                <div class="column is-8">
                  <div class="title">
                    <i18n.Translate>Payment details</i18n.Translate>
                  </div>
                  <FormProvider<Paid>
                    object={value}
                    valueHandler={valueHandler}
                  >
                    {/* <InputCurrency<Paid> name="deposit_total" readonly label={i18n.str`Deposit total`} /> */}
                    {order.refunded && (
                      <InputCurrency<Paid>
                        name="refund_amount"
                        readonly
                        label={i18n.str`Refunded amount`}
                      />
                    )}
                    {order.refunded && (
                      <InputCurrency<Paid>
                        name="refund_taken"
                        readonly
                        label={i18n.str`Refund taken`}
                      />
                    )}
                    <Input<Paid>
                      name="order_status"
                      readonly
                      label={i18n.str`Order status`}
                      toStr={(d) => {
                        switch (d) {
                          case "paid":
                            return i18n.str`Paid`;
                          case "claimed":
                            return i18n.str`Claimed`;
                          case "unpiad":
                            return i18n.str`Unpaid`;
                        }
                        return d;
                      }}
                    />
                    <TextField<Paid>
                      name="order_status_url"
                      label={i18n.str`Status URL`}
                    >
                      <a
                        target="_blank"
                        rel="noreferrer"
                        href={order.order_status_url}
                      >
                        {order.order_status_url}
                      </a>
                    </TextField>
                    {refundURI && (
                      <TextField<Paid>
                        name="order_status_url"
                        label={i18n.str`Refund URI`}
                      >
                        <a target="_blank" rel="noreferrer" href={refundURI}>
                          {refundURI}
                        </a>
                      </TextField>
                    )}
                  </FormProvider>
                </div>
              </div>
            </section>

            {order.contract_terms.products?.length ? (
              <Fragment>
                <div class="title">
                  <i18n.Translate>Product list</i18n.Translate>
                </div>
                <ProductList list={order.contract_terms.products} />
              </Fragment>
            ) : undefined}

            {!value.contract_terms ? undefined : (
              <ContractTerms value={value.contract_terms} />
            )}
          </div>
          <div class="column" />
        </div>
      </section>
    </div>
  );
}

function UnpaidPage({
  id,
  order,
}: {
  id: string;
  order: TalerMerchantApi.CheckPaymentUnpaidResponse;
}) {
  const [value, valueHandler] = useState<Partial<Unpaid>>(order);
  const { i18n } = useTranslationContext();
  const [preferences] = usePreference();

  return (
    <div>
      <section class="hero is-hero-bar">
        <div class="hero-body">
          <div class="level">
            <div class="level-left">
              <div class="level-item">
                <h1 class="title">
                  <i18n.Translate>Order</i18n.Translate> #{id}
                </h1>
              </div>
              <div class="tag is-dark">
                <i18n.Translate>Unpaid</i18n.Translate>
              </div>
            </div>
          </div>

          <div class="level">
            <div class="level-left" style={{ maxWidth: "100%" }}>
              <div class="level-item" style={{ maxWidth: "100%" }}>
                <div
                  class="content"
                  style={{
                    whiteSpace: "nowrap",
                    overflow: "hidden",
                    textOverflow: "ellipsis",
                  }}
                >
                  <p>
                    <b>
                      <i18n.Translate>Payment link</i18n.Translate>:
                    </b>{" "}
                    <a
                      href={order.order_status_url}
                      rel="nofollow"
                      target="new"
                    >
                      {order.order_status_url}
                    </a>
                  </p>
                  {/* <p>
                    <b>
                      <i18n.Translate>Created at</i18n.Translate>:
                    </b>{" "}
                    {order.creation_time.t_s === "never"
                      ? i18n.str`Never`
                      : format(
                          new Date(order.creation_time.t_s * 1000),
                          datetimeFormatForPreferences(preferences),
                        )}
                  </p> */}
                </div>
              </div>
            </div>
          </div>
        </div>
      </section>

      <section>
        <div
          style={{ width: "100%", display: "flex", justifyContent: "center" }}
        >
          <QR_Taler
            uri={Result.unpack(TalerUris.fromString(value.taler_pay_uri!))}
          />
        </div>
      </section>

      <section class="section is-main-section">
        <div class="columns">
          <div class="column" />
          <div class="column is-four-fifths">
            <FormProvider<Unpaid> object={value} valueHandler={valueHandler}>
              <Input<Unpaid>
                readonly
                name="summary"
                label={i18n.str`Summary`}
                tooltip={i18n.str`Human-readable description of the whole purchase`}
              />
              <InputCurrency<Unpaid>
                readonly
                name="total_amount"
                label={i18n.str`Amount`}
                tooltip={i18n.str`Total price for the transaction`}
              />
              <Input<Paid>
                name="order_status"
                readonly
                label={i18n.str`Order status`}
                toStr={(d) => {
                  switch (d) {
                    case "paid":
                      return i18n.str`Paid`;
                    case "claimed":
                      return i18n.str`Claimed`;
                    case "unpiad":
                      return i18n.str`Unpaid`;
                  }
                  return d;
                }}
              />
              <Input<Unpaid>
                name="order_status_url"
                readonly
                label={i18n.str`Order status URL`}
              />
              <TextField<Unpaid>
                name="taler_pay_uri"
                label={i18n.str`Payment URI`}
              >
                <a target="_blank" rel="noreferrer" href={value.taler_pay_uri}>
                  {value.taler_pay_uri}
                </a>
              </TextField>
            </FormProvider>
          </div>
          <div class="column" />
        </div>
      </section>
    </div>
  );
}

export function DetailPage({
  id,
  selected,
  onRefunded,
  onBack,
  onSelectWireTransfer,
}: Props): VNode {
  const [showRefund, setShowRefund] = useState<string | undefined>(undefined);
  const { i18n } = useTranslationContext();
  const DetailByStatus = function () {
    switch (selected.order_status) {
      case "claimed":
        return <ClaimedPage id={id} order={selected} />;
      case "paid":
        return (
          <PaidPage
            id={id}
            order={selected}
            onRefund={setShowRefund}
            onWireTransferSelection={onSelectWireTransfer}
          />
        );
      case "unpaid":
        return <UnpaidPage id={id} order={selected} />;
      default:
        return (
          <div>
            <i18n.Translate>
              Unknown order status. This is an error, please contact the
              administrator.
            </i18n.Translate>
          </div>
        );
    }
  };

  return (
    <Fragment>
      {DetailByStatus()}
      {showRefund && (
        <RefundModal
          order={selected}
          id={id}
          onCancel={() => setShowRefund(undefined)}
          onConfirmed={() => {
            onRefunded();
            setShowRefund(undefined);
          }}
        />
      )}
      <div class="columns">
        <div class="column" />
        <div class="column is-four-fifths">
          <div class="buttons is-right mt-5">
            <button class="button" onClick={onBack}>
              <i18n.Translate>Back</i18n.Translate>
            </button>
          </div>
        </div>
        <div class="column" />
      </div>
    </Fragment>
  );
}
export function getOrderAmountAndMaxDepositFee(
  order: TalerMerchantApi.CheckPaymentPaidResponse,
) {
  if (
    order.contract_terms.version === undefined ||
    order.contract_terms.version === MerchantContractVersion.V0
  ) {
    const amount = Amounts.parseOrThrow(order.contract_terms.amount);
    const maxDepositFee = Amounts.parseOrThrow(order.contract_terms.max_fee);
    return { amount, maxDepositFee };
  }
  if (order.contract_terms.version === MerchantContractVersion.V1) {
    if (order.choice_index === undefined) return "v1-without-index" as const;
    if (order.choice_index > order.contract_terms.choices.length)
      return "v1-wrong-index" as const;
    const choice = order.contract_terms.choices[order.choice_index];
    const amount = Amounts.parseOrThrow(choice.amount);
    const maxDepositFee = Amounts.parseOrThrow(choice.max_fee);
    return { amount, maxDepositFee };
  }
  assertUnreachable(order.contract_terms.version);
}

function CardTableIncoming({
  transfers,
  onSelected,
}: {
  transfers: TransactionWireTransfer[];
  onSelected: (id: number) => void;
}): VNode {
  const { i18n } = useTranslationContext();
  const [preferences] = usePreference();
  const { config } = useSessionContext();
  return (
    <div class="card has-table">
      <div class="card-content">
        <div class="b-table has-pagination">
          <div class="table-wrapper has-mobile-cards">
            <div class="table-container">
              <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
                <thead>
                  <tr>
                    <th>
                      <i18n.Translate>Date</i18n.Translate>
                    </th>
                    <th>
                      <i18n.Translate>Amount</i18n.Translate>
                    </th>
                    <th>
                      <i18n.Translate>Status</i18n.Translate>
                    </th>
                    <th></th>
                  </tr>
                </thead>
                <tbody>
                  {transfers.map((i, idx) => {
                    return (
                      <tr key={i.wtid}>
                        <td>
                          {i.execution_time
                            ? i.execution_time.t_s == "never"
                              ? i18n.str`never`
                              : format(
                                  i.execution_time.t_s * 1000,
                                  datetimeFormatForPreferences(preferences),
                                )
                            : i18n.str`unknown`}
                        </td>
                        <td>
                          <RenderAmountBulma
                            value={Amounts.parseOrThrow(i.amount)}
                            specMap={config.currencies}
                          />
                        </td>
                        <td>
                          {i.confirmed
                            ? i18n.str`confirmed`
                            : i18n.str`unconfirmed`}
                        </td>
                        <td>
                          <button
                            type="button"
                            class="button is-info "
                            disabled={
                              i.expected_transfer_serial_id === undefined
                            }
                            onClick={() => {
                              if (i.expected_transfer_serial_id === undefined)
                                return;
                              onSelected(i.expected_transfer_serial_id);
                            }}
                          >
                            <i18n.Translate>Details</i18n.Translate>
                          </button>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
