/* Dashboard cards. Commit model: INSTANT (declared in DashboardScreen.jsx) —
   no Save button anywhere; each control confirms itself, consequential ones
   with an undo toast and irreversible ones with a confirm dialog. */

const {
  Card, CardHeader, CardTitle, CardDescription, CardAction, CardPanel, CardFooter,
  Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
  Button: CardsButton, Badge: CardsBadge, Separator: CardsSeparator, Meter,
  Tabs, TabsList, TabsTab, MenuItem: RowMenuItem, MenuSeparator: RowMenuSeparator,
  Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent,
} = window.OriginDesignSystem_7c998b;

function RowMenu({ label, children }) {
  return (
    <Floating
      align="end"
      width="13rem"
      label={label}
      trigger={<CardsButton variant="ghost" size="icon-sm" aria-label={label}><Icon name="more-horizontal" /></CardsButton>}
    >
      {children}
    </Floating>
  );
}

/* ── Payouts ─────────────────────────────────────────────────────────── */

function PayoutQueueCard({ payouts, approver, members, now, onApprove, onReject, onNavigate }) {
  const queue = awaitingApprovalPayouts(payouts);
  const approvable = approvablePayouts(payouts, approver);
  const blocked = queue.filter(PAYOUT_FLAGS.isBlocked);
  const overLimit = queue.filter((p) => !PAYOUT_FLAGS.isBlocked(p) && PAYOUT_FLAGS.isAboveLimit(p, approver));
  const total = sumBy(queue, "amount");

  return (
    <Card className="fd-card fd-card--table">
      <CardHeader>
        <CardTitle>Payouts awaiting approval</CardTitle>
        <CardDescription>
          {formatMoney(total)} across {queue.length} payouts — {approvable.length} you can approve now
          {blocked.length ? ", " + blocked.length + " waiting on compliance review" : ""}
          {overLimit.length ? ", " + overLimit.length + " above your " + formatMoney(approver.approvalLimit) + " limit" : ""}.
        </CardDescription>
      </CardHeader>
      <div className="fd-card-table">
        <Table>
          <TableHeader>
            <TableRow>
              <TableHead>Payout</TableHead>
              <TableHead className="fd-num">Amount</TableHead>
              <TableHead className="fd-drop-md">Expected</TableHead>
              <TableHead className="fd-actions-head">Approval</TableHead>
            </TableRow>
          </TableHeader>
          <TableBody>
            {queue.map((payout) => {
              const isBlocked = PAYOUT_FLAGS.isBlocked(payout);
              const above = !isBlocked && PAYOUT_FLAGS.isAboveLimit(payout, approver);
              const higher = above ? members.filter((m) => m.approvalLimit >= payout.amount) : [];
              const transitions = payoutTransitions(payout, approver);
              const approve = transitions.find((t) => t.id === "approve");
              const reject = transitions.find((t) => t.id === "reject");
              return (
                <TableRow key={payout.id} className={isBlocked || above ? "fd-row--recessed" : ""}>
                  <TableCell>
                    <span className="fd-record">
                      <span className="fd-record__name">{payout.destination}</span>
                      <span className="fd-record__meta"><code>{payout.id}</code> · {payout.account}</span>
                    </span>
                  </TableCell>
                  <TableCell className="fd-num fd-amount">{formatMoney(payout.amount)}</TableCell>
                  <TableCell className="fd-drop-md">
                    <span title={formatAbsolute(payout.expectedAt)}>{formatWhen(payout.expectedAt, now)}</span>
                    <span className="fd-sub">{formatCountdown(payout.expectedAt, now)}</span>
                  </TableCell>
                  <TableCell className="fd-actions">
                    {isBlocked ? (
                      <span className="fd-waiting">Waiting on {payout.blockedBy.team} — {payout.blockedBy.reason}</span>
                    ) : above ? (
                      <span className="fd-waiting">Above your limit — {higher.length ? higher.map((m) => m.name).join(" or ") : "nobody here"} can release it</span>
                    ) : (
                      <span className="fd-actions__row">
                        <CardsButton size="xs" onClick={() => onApprove(payout)}>{approve.label.replace(" payout", "")}</CardsButton>
                        <CardsButton size="xs" variant="destructive-outline" onClick={() => onReject(payout)}>{reject.label.replace(" payout", "")}</CardsButton>
                      </span>
                    )}
                  </TableCell>
                </TableRow>
              );
            })}
          </TableBody>
        </Table>
      </div>
      <CardFooter className="fd-card-footer">
        <span className="fd-footnote">{formatMoney(pendingPayoutTotal(payouts))} committed to payouts in total, including approved and in transit.</span>
        <CardsButton variant="ghost" size="sm" onClick={() => onNavigate("/payouts")}>All payouts<Icon name="arrow-right" /></CardsButton>
      </CardFooter>
    </Card>
  );
}

/* ── Payments ────────────────────────────────────────────────────────── */

const PAYMENT_TABS = [
  { value: "all", label: "All", predicate: () => true },
  { value: "succeeded", label: "Succeeded", predicate: (p) => p.status === "succeeded" },
  { value: "attention", label: "Needs attention", predicate: (p, disputes) => PAYMENT_FLAGS.needsAttention(p, disputes) },
];
const PAYMENTS_SHOWN = 6;

function PaymentsCard({ payments, disputes, periodLabel, now, onCapture, onRetry, onRefund, onNavigate }) {
  const [tab, setTab] = React.useState("all");
  const spec = PAYMENT_TABS.find((t) => t.value === tab);
  const rows = payments.filter((p) => spec.predicate(p, disputes)).sort((a, b) => b.createdAt - a.createdAt);
  const shown = rows.slice(0, PAYMENTS_SHOWN);

  return (
    <Card className="fd-card fd-card--table">
      <CardHeader>
        <CardTitle>Payments</CardTitle>
        <CardDescription>{periodLabel}, newest first.</CardDescription>
      </CardHeader>
      <div className="fd-card-tabs">
        <Tabs value={tab} onValueChange={setTab}>
          <TabsList variant="underline" size="sm">
            {PAYMENT_TABS.map((t) => (
              <TabsTab key={t.value} value={t.value} size="sm">
                {t.label}<span className="fd-tab-count">{payments.filter((p) => t.predicate(p, disputes)).length}</span>
              </TabsTab>
            ))}
          </TabsList>
        </Tabs>
      </div>
      {shown.length === 0 ? (
        <CardPanel>
          <Empty>
            <EmptyHeader>
              <EmptyMedia variant="icon"><Icon name="check" size={18} /></EmptyMedia>
              <EmptyTitle>Nothing needs attention</EmptyTitle>
              <EmptyDescription>No payment in the {periodLabel.toLowerCase()} failed or picked up a dispute.</EmptyDescription>
            </EmptyHeader>
            <EmptyContent>
              <CardsButton variant="outline" size="sm" onClick={() => setTab("all")}>Show all payments</CardsButton>
            </EmptyContent>
          </Empty>
        </CardPanel>
      ) : (
        <div className="fd-card-table">
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>Payment</TableHead>
                <TableHead className="fd-drop-lg">Method</TableHead>
                <TableHead className="fd-num">Amount</TableHead>
                <TableHead>Status</TableHead>
                <TableHead className="fd-drop-md">Created</TableHead>
                <TableHead className="fd-actions-head"><span className="o-sr">Actions</span></TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {shown.map((payment) => {
                const disputed = PAYMENT_FLAGS.hasOpenDispute(payment, disputes);
                const transitions = paymentTransitions(payment);
                return (
                  <TableRow key={payment.id}>
                    <TableCell>
                      <span className="fd-record">
                        <span className="fd-record__name">{payment.customer}</span>
                        <span className="fd-record__meta"><code>{payment.id}</code>{payment.failureReason ? " · " + payment.failureReason : ""}</span>
                      </span>
                    </TableCell>
                    <TableCell className="fd-drop-lg fd-muted">{labelOf(PAYMENT_METHODS, payment.method)}</TableCell>
                    <TableCell className="fd-num fd-amount">{formatMoney(payment.amount)}</TableCell>
                    <TableCell>
                      <span className="fd-status">
                        <StatusBadge values={PAYMENT_STATUS} value={payment.status} />
                        {disputed ? <CardsBadge size="sm" variant="warning">Disputed</CardsBadge> : null}
                      </span>
                    </TableCell>
                    <TableCell className="fd-drop-md fd-muted" title={formatAbsolute(payment.createdAt)}>{formatWhen(payment.createdAt, now)}</TableCell>
                    <TableCell className="fd-actions">
                      <RowMenu label={"Actions for " + payment.id}>
                        {(close) => (
                          <>
                            <RowMenuItem onClick={() => { onNavigate("/payments"); close(); }}>Open in payments</RowMenuItem>
                            {payment.status === "succeeded" || payment.status === "refunded" ? (
                              <RowMenuItem onClick={close}>Download receipt</RowMenuItem>
                            ) : null}
                            {transitions.length ? <RowMenuSeparator /> : null}
                            {transitions.map((t) => (
                              <RowMenuItem
                                key={t.id}
                                variant={t.destructive ? "destructive" : "default"}
                                onClick={() => {
                                  close();
                                  if (t.id === "capture") onCapture(payment);
                                  if (t.id === "retry") onRetry(payment);
                                  if (t.id === "refund") onRefund(payment);
                                }}
                              >{t.label}</RowMenuItem>
                            ))}
                          </>
                        )}
                      </RowMenu>
                    </TableCell>
                  </TableRow>
                );
              })}
            </TableBody>
          </Table>
        </div>
      )}
      <CardFooter className="fd-card-footer">
        <span className="fd-footnote">
          {shown.length ? "Showing 1–" + shown.length + " of " + rows.length : "No rows"} · {periodLabel.toLowerCase()}
        </span>
        <CardsButton variant="ghost" size="sm" onClick={() => onNavigate("/payments")}>All payments<Icon name="arrow-right" /></CardsButton>
      </CardFooter>
    </Card>
  );
}

/* ── Balance ─────────────────────────────────────────────────────────── */

function BalanceCard({ balance, payouts, disputes, onNavigate }) {
  const b = balanceBreakdown(balance, payouts, disputes);
  return (
    <Card className="fd-card">
      <CardHeader>
        <CardTitle>Balance</CardTitle>
        <CardDescription>{balance.bank}</CardDescription>
      </CardHeader>
      <CardPanel className="fd-stack">
        <div>
          <div className="fd-figure">{formatMoney(b.available)}</div>
          <div className="fd-figure__label">Available now</div>
        </div>
        <Meter value={b.available} max={b.total} aria-label="Available share of total balance" />
        <dl className="fd-defs">
          <div><dt>Committed to payouts</dt><dd>{formatMoney(b.committed)}</dd></div>
          <div><dt>Held against open disputes</dt><dd>{formatMoney(b.reserved)}</dd></div>
          <div><dt>In transit to bank</dt><dd>{formatMoney(inTransitTotal(payouts))}</dd></div>
          <div className="fd-defs__total"><dt>Total balance</dt><dd>{formatMoney(b.total)}</dd></div>
        </dl>
      </CardPanel>
      <CardFooter className="fd-card-footer">
        <CardsButton variant="ghost" size="sm" onClick={() => onNavigate("/balances")}>Balance history<Icon name="arrow-right" /></CardsButton>
      </CardFooter>
    </Card>
  );
}

/* ── Disputes ────────────────────────────────────────────────────────── */

function DisputesCard({ disputes, now, onNavigate }) {
  const open = openDisputes(disputes);
  const needing = disputesNeedingEvidence(disputes);
  return (
    <Card className="fd-card">
      <CardHeader>
        <CardTitle>Disputes needing evidence</CardTitle>
        <CardDescription>{needing.length} of {open.length} open disputes are waiting on you, {formatMoney(disputeExposure(disputes))} held in total.</CardDescription>
      </CardHeader>
      <CardPanel className="fd-list">
        {needing.map((dispute) => {
          const soon = DISPUTE_FLAGS.isClosingSoon(dispute, now);
          return (
            <div className="fd-list__row" key={dispute.id}>
              <div className="fd-list__main">
                <span className="fd-record__name">{dispute.customer}</span>
                <span className="fd-record__meta"><code>{dispute.id}</code> · {dispute.reason}</span>
              </div>
              <div className="fd-list__side">
                <span className="fd-amount">{formatMoney(dispute.amount)}</span>
                <span className={soon ? "fd-clock fd-clock--danger" : "fd-clock fd-clock--warning"} title={formatAbsolute(dispute.evidenceDueAt)}>
                  {formatCountdown(dispute.evidenceDueAt, now)}
                </span>
              </div>
              <CardsButton size="xs" variant="outline" onClick={() => onNavigate("/disputes/" + dispute.id)}>Submit evidence</CardsButton>
            </div>
          );
        })}
      </CardPanel>
      <CardFooter className="fd-card-footer">
        <CardsButton variant="ghost" size="sm" onClick={() => onNavigate("/disputes")}>All {disputes.length} disputes<Icon name="arrow-right" /></CardsButton>
      </CardFooter>
    </Card>
  );
}

/* ── Volume by day ───────────────────────────────────────────────────── */

/* The same arithmetic the net-volume tile does, bucketed by day, so the bars
   add back to the figure above them over the same scoped array. */
function VolumeCard({ payments, periodLabel, now, days }) {
  const buckets = volumeByDay(payments, now, days);
  const busiest = buckets.slice().sort((a, b) => b.amount - a.amount)[0];
  const failed = failedPayments(payments);
  return (
    <Card className="fd-card">
      <CardHeader>
        <CardTitle>Net volume by day</CardTitle>
        <CardDescription>{formatMoney(netVolume(payments))} across {settledAttempts(payments).length} payments with an outcome, {periodLabel.toLowerCase()}.</CardDescription>
      </CardHeader>
      <CardPanel>
        <DayChart
          buckets={buckets}
          series={[{ key: "amount", label: "Net volume", rows: [{ key: "rows", noun: "payment" }] }]}
          format={formatMoney}
          label="Net volume a day"
          note={busiest && busiest.amount ? "Busiest day " + formatDay(busiest.at) + ", " + formatMoney(busiest.amount) + " across " + busiest.rows.length + " payments." : "Nothing settled in this period."}
        />
      </CardPanel>
      <CardFooter className="fd-card-footer">
        <span className="fd-footnote">Refunds are subtracted on the day the payment was taken. {failed.length} failed payments, {formatMoney(sumBy(failed, "amount"))}, are outside every bar.</span>
      </CardFooter>
    </Card>
  );
}

/* ── Card spend waiting on review ─────────────────────────────────────── */

function ExpenseReviewCard({ expenses, cards, members, policy, now, onApprove, onRun, onNavigate }) {
  const waiting = expensesAwaitingReview(expenses);
  const approvable = reviewableExpenses(expenses, policy);
  const nameOf = (id) => (members.find((m) => m.id === id) || { name: "somebody who has left" }).name;
  const cardOf = (id) => cards.find((c) => c.id === id);
  return (
    <Card className="fd-card">
      <CardHeader>
        <CardTitle>Card spend waiting on you</CardTitle>
        <CardDescription>
          {approvable.length} of {waiting.length} expenses under review can be approved now, {formatMoney(sumBy(approvable, "amount"))} in total
          {waiting.length - approvable.length ? "; " + (waiting.length - approvable.length) + " are still owed a receipt" : ""}.
        </CardDescription>
      </CardHeader>
      <CardPanel className="fd-list">
        {waiting.map((expense) => {
          const owed = EXPENSE_FLAGS.needsReceipt(expense, policy);
          const on = cardOf(expense.cardId);
          return (
            <div className={owed ? "fd-list__row fd-row--recessed" : "fd-list__row"} key={expense.id}>
              <div className="fd-list__main">
                <span className="fd-record__name">{expense.merchant}</span>
                <span className="fd-record__meta"><code>{expense.id}</code> · {on ? on.label : "card closed"} · {nameOf(expense.spenderId)}</span>
              </div>
              <div className="fd-list__side">
                <span className="fd-amount">{formatMoney(expense.amount)}</span>
                <span className="fd-sub" title={formatAbsolute(expense.occurredAt)}>{formatWhen(expense.occurredAt, now)}</span>
              </div>
              {owed
                ? <span className="fd-waiting">Waiting on {nameOf(expense.spenderId)} — no receipt on {labelOf(EXPENSE_CATEGORIES, expense.category).toLowerCase()} spend</span>
                : <span className="fd-actions__row">
                  <CardsButton size="xs" onClick={() => onApprove(expense)}>Approve</CardsButton>
                  <CardsButton size="xs" variant="outline" onClick={() => onRun(expense, { id: "query_expense" })}>Query</CardsButton>
                </span>}
            </div>
          );
        })}
      </CardPanel>
      <CardFooter className="fd-card-footer">
        <span className="fd-footnote">Receipts are required over {formatMoney(policy.receiptThresholdCents)}.</span>
        <CardsButton variant="ghost" size="sm" onClick={() => onNavigate("/expenses")}>All expenses<Icon name="arrow-right" /></CardsButton>
      </CardFooter>
    </Card>
  );
}

/* ── Method mix ──────────────────────────────────────────────────────── */

function MethodMixCard({ payments, periodLabel }) {
  const succeeded = succeededPayments(payments);
  const mix = methodMix(payments, PAYMENT_METHODS);
  const total = sumBy(succeeded, "amount");
  return (
    <Card className="fd-card">
      <CardHeader>
        <CardTitle>How the volume arrived</CardTitle>
        <CardDescription>{formatMoney(total)} succeeded across {succeeded.length} payments, {periodLabel.toLowerCase()}.</CardDescription>
      </CardHeader>
      <CardPanel className="fd-stack">
        <MixRows rows={mix} total={total} unitLabel="succeeded volume" />
      </CardPanel>
    </Card>
  );
}

Object.assign(window, { PayoutQueueCard, PaymentsCard, BalanceCard, DisputesCard, MethodMixCard, VolumeCard, ExpenseReviewCard, RowMenu });
