/* Cards — the workspace's corporate cards, and one card's own ledger.
   Commit model: INSTANT. Freezing and unfreezing apply immediately with an undo
   toast; cancelling a card is irreversible and opens a confirm dialog; issuing
   one needs four fields, so it opens a staged dialog from this instant screen.
   Data state: populated.
   Primary display: a canvas of card tiles, not a table — the question this
   destination answers is "how much of this card's limit is left", which a meter
   answers and a row does not. The ledger lives on the card's own route.
   Every limit and every spend figure is measured over one rolling window,
   CARD_WINDOW_DAYS, named once in metrics.js and stated in words below. */
(() => {
  const {
    Card, CardHeader, CardTitle, CardDescription, CardPanel, CardFooter, CardAction,
    Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
    Button, Badge, Avatar, Meter, Alert, AlertTitle, AlertDescription,
  } = window.OriginDesignSystem_7c998b;

  function LimitMeter({ use }) {
    return (
      <div className="fd-part">
        <div className="fd-spread">
          <span className="fd-figure">{formatMoney(use.spent)}</span>
          <span className={use.over ? "fd-clock fd-clock--danger" : use.near ? "fd-clock fd-clock--warning" : "fd-footnote"}>
            {use.limit > 0
              ? use.over ? formatMoney(use.spent - use.limit) + " over the limit" : formatMoney(use.limit - use.spent) + " left"
              : "No limit set"}
          </span>
        </div>
        <Meter value={Math.min(use.spent, use.limit)} max={use.limit || 1} aria-label={"Spend against the " + CARD_WINDOW_DAYS + "-day limit"} />
        <span className="fd-footnote">{formatPercent(use.share)} of {formatMoney(use.limit)} over the last {CARD_WINDOW_DAYS} days, across {use.rows.length} expenses.</span>
      </div>
    );
  }

  function CardTile({ card, holder, use, waiting, onOpen, onRun }) {
    const transitions = cardTransitions(card);
    return (
      <Card className={card.status === "cancelled" ? "fd-card fd-row--recessed" : "fd-card"}>
        <CardHeader>
          <CardTitle>{card.label}</CardTitle>
          <CardDescription>
            <span className="fd-pan">•••• {card.last4}</span> · {labelOf(CARD_TYPES, card.type)}
          </CardDescription>
          <CardAction><StatusBadge values={CARD_STATUS} value={card.status} /></CardAction>
        </CardHeader>
        <CardPanel className="fd-stack">
          <span className="fd-holder">
            <Avatar size={24} src={holder.avatar} alt="" fallback={holder.name.slice(0, 1)} />
            {holder.name}
          </span>
          {card.status === "cancelled" ? (
            <span className="fd-footnote">Cancelled {formatWhen(card.cancelledAt, MERIDIAN_NOW)} by {card.cancelledBy} — {card.cancelReason}. Nothing can be spent on it.</span>
          ) : card.status === "pending_activation" ? (
            <span className="fd-waiting">Waiting on {holder.name} to activate it. Nothing has been spent yet.</span>
          ) : (
            <LimitMeter use={use} />
          )}
          <span className="fd-meta">
            <span>Expires {formatDay(card.expiresAt)}</span>
            <span>Opened {formatDay(card.openedAt)}</span>
            {waiting ? <span>{waiting}</span> : null}
          </span>
        </CardPanel>
        <CardFooter className="fd-card-footer">
          <Button variant="ghost" size="sm" onClick={onOpen}>Open card<Icon name="arrow-right" /></Button>
          {transitions.length ? <RowActions transitions={transitions} onRun={onRun} label={"Actions for " + card.label} /> : null}
        </CardFooter>
      </Card>
    );
  }

  function CardsScreen({ data, now, onNavigate, onCardTransition, onIssueCard, issuer }) {
    const policy = data.policy;
    const live = liveCards(data.cards);
    const atRisk = cardsAtRisk(data.cards, data.expenses, now, policy);
    const windowSpend = cardSpendTotal(expensesInPeriod(data.expenses, CARD_WINDOW_DAYS, now));
    const holderOf = (card) => data.members.find((m) => m.id === card.holderId) || { name: "Unassigned", avatar: null };
    const useOf = (card) => cardUtilisation(card, data.expenses, now, policy);
    const ordered = live.slice().sort((a, b) => useOf(b).share - useOf(a).share).concat(data.cards.filter((c) => c.status === "cancelled"));

    const newCard = (
      <Button size="sm" disabled={!issuer.canIssueCards} onClick={onIssueCard}><Icon name="plus" />New card</Button>
    );

    return (
      <div className="fd-page">
        <PageHeader
          path="/cards"
          title="Cards"
          actions={issuer.canIssueCards ? newCard : <FloatingTip side="bottom" label={"Only an admin can issue a card — you are set up as " + labelOf(TEAM_ROLES, issuer.teamRole).toLowerCase() + " in team and approvals."}>{newCard}</FloatingTip>}
        />

        <div className="fd-metrics">
          <MetricTile icon="receipt" label={"Spend, last " + CARD_WINDOW_DAYS + " days"} value={formatMoney(windowSpend)} qualifier={"Settled spend across all " + data.cards.length + " cards, the window every limit is measured over"} />
          <MetricTile icon="credit-card" label="Live cards" value={formatCount(live.length)} qualifier={live.filter(CARD_FLAGS.isSpendable).length + " active, " + live.filter((c) => c.status === "frozen").length + " frozen, " + live.filter((c) => c.status === "pending_activation").length + " not activated"} />
          <MetricTile icon="gauge" label="Near or past their limit" value={formatCount(atRisk.length)} qualifier={atRisk.length ? atRisk.map((c) => c.label).join(", ") + " — over " + formatPercent(policy.cardWarnShare) + " of the limit" : "Every card is under " + formatPercent(policy.cardWarnShare) + " of its limit"} />
          <MetricTile icon="inbox" label="Waiting on review" value={formatCount(reviewableExpenses(data.expenses, policy).length)} qualifier={formatMoney(sumBy(reviewableExpenses(data.expenses, policy), "amount")) + " of card spend you can approve now"} />
        </div>

        {atRisk.length ? (
          <Alert variant="warning">
            <AlertTitle>{atRisk.length === 1 ? atRisk[0].label + " is " + (useOf(atRisk[0]).over ? "past" : "close to") + " its limit" : atRisk.length + " cards are near or past their limit"}</AlertTitle>
            <AlertDescription>
              {atRisk.map((c) => c.label + " — " + formatMoney(useOf(c).spent) + " of " + formatMoney(c.spendLimit)).join(" · ")}. A card at its limit declines the next authorisation; raise the limit on the card, or freeze it.
            </AlertDescription>
          </Alert>
        ) : null}

        <div className="fd-cardgrid">
          {ordered.map((card) => (
            <CardTile
              key={card.id}
              card={card}
              holder={holderOf(card)}
              use={useOf(card)}
              waiting={CARD_FLAGS.isExpiringSoon(card, now) ? "Expires in " + formatCountdown(card.expiresAt, now).replace(" left", "") : null}
              onOpen={() => onNavigate("/cards/" + card.id)}
              onRun={(t) => onCardTransition(card, t)}
            />
          ))}
        </div>
      </div>
    );
  }

  /* One card. The figures are the same 30-day window the tiles use; the ledger
     below them is every expense ever put on the card, which the footer states. */
  function CardScreen({ data, now, cardId, onNavigate, onCardTransition, onExpenseTransition, onPostComment }) {
    const policy = data.policy;
    const card = data.cards.find((c) => c.id === cardId);
    const holder = data.members.find((m) => m.id === card.holderId) || { name: "Unassigned", avatar: null, email: "" };
    const use = cardUtilisation(card, data.expenses, now, policy);
    const ledger = expensesOnCard(data.expenses, card.id).slice().sort((a, b) => b.occurredAt - a.occurredAt);
    const reviewable = reviewableExpenses(use.rows, policy);
    const buckets = bucketBy(settledExpenses(use.rows), (e) => e.occurredAt, now, CARD_WINDOW_DAYS).map((b) => ({ at: b.at, spend: sumBy(b.rows, "amount"), rows: b.rows }));
    const mix = spendByCategory(use.rows, EXPENSE_CATEGORIES);

    return (
      <div className="fd-page">
        <PageHeader
          path="/cards/:id"
          title={card.label}
          actions={<Transitions transitions={cardTransitions(card)} onRun={(t) => onCardTransition(card, t)} size="default" />}
        />

        {card.status === "frozen" ? (
          <Alert variant="warning">
            <AlertTitle>Frozen {formatWhen(card.frozenAt, now)} by {card.frozenBy}</AlertTitle>
            <AlertDescription>{card.frozenReason}. Authorisations are declined until it is unfrozen; spend already settled still needs reviewing.</AlertDescription>
          </Alert>
        ) : card.status === "cancelled" ? (
          <Alert variant="info">
            <AlertTitle>Cancelled {formatWhen(card.cancelledAt, now)} by {card.cancelledBy}</AlertTitle>
            <AlertDescription>{card.cancelReason}. The ledger below is kept for the record; nothing more can be spent.</AlertDescription>
          </Alert>
        ) : null}

        <div className="fd-columns">
          <div className="fd-col">
            <Card className="fd-card">
              <CardHeader>
                <CardTitle>Spend by day</CardTitle>
                <CardDescription>{formatMoney(use.spent)} settled on this card over the last {CARD_WINDOW_DAYS} days — the window its limit is measured over.</CardDescription>
              </CardHeader>
              <CardPanel>
                <DayChart
                  buckets={buckets}
                  series={[{ key: "spend", label: card.label, rows: [{ key: "rows", noun: "expense" }] }]}
                  format={formatMoney}
                  label={"Spend a day on " + card.label}
                  note={use.rows.length + " expenses in the window; " + formatMoney(use.limit) + " limit."}
                />
              </CardPanel>
            </Card>

            <Card>
              <CardHeader>
                <CardTitle>Everything put on this card</CardTitle>
                <CardDescription>Newest first. {reviewable.length ? reviewable.length + " of them can be approved now." : "Nothing here is waiting on you."}</CardDescription>
              </CardHeader>
              <div className="fd-card-table">
                <Table variant="card">
                  <TableHeader>
                    <TableRow>
                      <TableHead>Expense</TableHead>
                      <TableHead className="fd-drop-md">Category</TableHead>
                      <TableHead>Status</TableHead>
                      <TableHead className="fd-num">Amount</TableHead>
                      <TableHead className="fd-num fd-drop-lg">Occurred</TableHead>
                      <TableHead className="fd-actions-head">Action</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {ledger.map((expense) => {
                      const waiting = EXPENSE_FLAGS.waitsOnSpender(expense, policy);
                      return (
                        <TableRow key={expense.id} className={waiting ? "fd-row--recessed" : ""}>
                          <TableCell>
                            <span className="fd-record">
                              <span className="fd-record__name">{expense.merchant}</span>
                              <span className="fd-record__meta"><code>{expense.id}</code></span>
                            </span>
                          </TableCell>
                          <TableCell className="fd-drop-md fd-muted">{labelOf(EXPENSE_CATEGORIES, expense.category)}</TableCell>
                          <TableCell>
                            <span className="fd-status">
                              <StatusBadge values={EXPENSE_STATUS} value={expense.status} />
                              {EXPENSE_FLAGS.needsReceipt(expense, policy) ? <Badge size="sm" variant="warning">No receipt</Badge> : null}
                            </span>
                            {waiting ? <span className="fd-sub">Waiting on {holder.name}</span> : null}
                          </TableCell>
                          <TableCell className="fd-num fd-amount">{formatMoney(expense.amount)}</TableCell>
                          <TableCell className="fd-num fd-muted fd-drop-lg" title={formatAbsolute(expense.occurredAt)}>{formatWhen(expense.occurredAt, now)}</TableCell>
                          <TableCell className="fd-actions">
                            <RowActions transitions={expenseTransitions(expense, policy)} onRun={(t) => onExpenseTransition(expense, t)} label={"Actions for " + expense.id} />
                          </TableCell>
                        </TableRow>
                      );
                    })}
                  </TableBody>
                </Table>
              </div>
              <CardFooter className="fd-card-footer">
                <span className="fd-footnote">{ledger.length} expenses since the card was opened; {use.rows.length} of them inside the {CARD_WINDOW_DAYS}-day window the figures above measure.</span>
                <Button variant="ghost" size="sm" onClick={() => onNavigate("/expenses")}>All expenses<Icon name="arrow-right" /></Button>
              </CardFooter>
            </Card>
          </div>

          <div className="fd-col">
            <Card className="fd-card">
              <CardHeader>
                <CardTitle>The card</CardTitle>
                <CardDescription><span className="fd-pan">•••• {card.last4}</span> · {labelOf(CARD_TYPES, card.type)}</CardDescription>
                <CardAction><StatusBadge values={CARD_STATUS} value={card.status} /></CardAction>
              </CardHeader>
              <CardPanel className="fd-stack">
                {card.status === "pending_activation"
                  ? <span className="fd-waiting">Waiting on {holder.name} to activate it. Nothing has been spent yet.</span>
                  : <LimitMeter use={use} />}
                <dl className="fd-defs">
                  <div><dt>Holder</dt><dd><span className="fd-holder"><Avatar size={20} src={holder.avatar} alt="" fallback={holder.name.slice(0, 1)} />{holder.name}</span></dd></div>
                  <div><dt>{CARD_WINDOW_DAYS}-day limit</dt><dd>{formatMoney(card.spendLimit)}</dd></div>
                  <div><dt>Opened</dt><dd title={formatAbsolute(card.openedAt)}>{formatDay(card.openedAt)}</dd></div>
                  <div><dt>Expires</dt><dd>{formatDay(card.expiresAt)}{CARD_FLAGS.isExpiringSoon(card, now) ? " · " + formatCountdown(card.expiresAt, now) : ""}</dd></div>
                  <div className="fd-defs__total"><dt>Spent in the window</dt><dd>{formatMoney(use.spent)}</dd></div>
                </dl>
              </CardPanel>
            </Card>

            <Card className="fd-card">
              <CardHeader>
                <CardTitle>Where it went</CardTitle>
                <CardDescription>{formatMoney(use.spent)} of settled spend, last {CARD_WINDOW_DAYS} days.</CardDescription>
              </CardHeader>
              <CardPanel>
                {mix.length
                  ? <MixRows rows={mix} total={use.spent} unitLabel="spend on this card" />
                  : <span className="fd-footnote">Nothing has settled on this card in the last {CARD_WINDOW_DAYS} days.</span>}
              </CardPanel>
            </Card>

            <ThreadCard
              record={{ type: "card", id: card.id, holderId: card.holderId }}
              data={data}
              signedInId={MERIDIAN_SIGNED_IN}
              now={now}
              onPost={onPostComment}
              description={card.status === "frozen"
                ? "Between the holder and whoever can unfreeze it. Mention somebody to put it in their queue."
                : "Between the holder and whoever reviews the spend. Mention somebody to put it in their queue."}
            />
          </div>
        </div>
      </div>
    );
  }

  Object.assign(window, { CardsScreen, CardScreen });
})();
