"use client";

import { FormEvent, useMemo, useState } from "react";
import {
  Banknote,
  CircleDollarSign,
  Eye,
  FilePlus2,
  FileText,
  HandCoins,
  Plus,
  ReceiptText,
  Search,
  TriangleAlert,
  WalletCards,
} from "lucide-react";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog } from "@/components/ui/dialog";
import { Input, Textarea } from "@/components/ui/input";
import { Select } from "@/components/ui/select";
import { Table } from "@/components/ui/table";
import {
  BILLING_STATUS_LABELS,
  BILLING_STATUS_VALUES,
  INVOICE_STATUS_LABELS,
  PAYMENT_METHOD_LABELS,
  PAYMENT_METHOD_VALUES,
  addBillingCharge,
  addBillingPayment,
  calculateBillingSummary,
  formatBillingPeriod,
  formatCny,
  toBillingStatementView,
} from "@/modules/billing/types";
import type {
  BillingCharge,
  BillingStatement,
  BillingStatementView,
  BillingStatus,
  InvoiceStatus,
  PaymentMethod,
} from "@/modules/billing/types";

type BillingWorkspaceClientProps = {
  initialStatements: BillingStatement[];
};

type PaymentFormState = {
  amountYuan: string;
  method: PaymentMethod;
  paidAt: string;
  reference: string;
  note: string;
};

type ChargeFormState = {
  category: string;
  description: string;
  quantity: string;
  serviceDate: string;
  unitPriceYuan: string;
};

type DialogState =
  | { kind: "detail"; statementId: string }
  | { kind: "payment"; statementId: string; form: PaymentFormState }
  | { kind: "charge"; statementId: string; form: ChargeFormState };

const STATUS_SORT_ORDER: Record<BillingStatus, number> = {
  overdue: 0,
  partial: 1,
  pending: 2,
  paid: 3,
};

const chargeCategoryOptions = [
  { value: "床位服务", label: "床位服务" },
  { value: "护理服务", label: "护理服务" },
  { value: "膳食服务", label: "膳食服务" },
  { value: "健康管理", label: "健康管理" },
  { value: "康复服务", label: "康复服务" },
  { value: "生活用品", label: "生活用品" },
  { value: "其他费用", label: "其他费用" },
];

function formatDate(value: string): string {
  return new Date(value).toLocaleDateString("zh-CN");
}

function formatDateTime(value: string): string {
  return new Date(value).toLocaleString("zh-CN");
}

function toDateInputValue(date: Date): string {
  const localDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
  return localDate.toISOString().slice(0, 10);
}

function toDateTimeInputValue(date: Date): string {
  const localDate = new Date(date.getTime() - date.getTimezoneOffset() * 60 * 1000);
  return localDate.toISOString().slice(0, 16);
}

function parseYuanToCents(value: string): number | undefined {
  const amount = Number(value);
  if (!Number.isFinite(amount) || amount <= 0) {
    return undefined;
  }
  return Math.round(amount * 100);
}

function getStatusVariant(status: BillingStatus): "danger" | "secondary" | "success" | "warning" {
  if (status === "paid") {
    return "success";
  }
  if (status === "overdue") {
    return "danger";
  }
  if (status === "partial") {
    return "warning";
  }
  return "secondary";
}

function getInvoiceVariant(status: InvoiceStatus): "secondary" | "success" | "warning" {
  if (status === "issued") {
    return "success";
  }
  if (status === "pending") {
    return "warning";
  }
  return "secondary";
}

export function BillingWorkspaceClient({ initialStatements }: BillingWorkspaceClientProps): React.ReactElement {
  const [statements, setStatements] = useState(initialStatements);
  const [query, setQuery] = useState("");
  const [statusFilter, setStatusFilter] = useState<"all" | BillingStatus>("all");
  const [dialog, setDialog] = useState<DialogState>();
  const [message, setMessage] = useState("");
  const [referenceDate] = useState(() => new Date());

  const statementViews = useMemo(
    () =>
      statements
        .map((statement) => toBillingStatementView(statement, referenceDate))
        .sort((left, right) => STATUS_SORT_ORDER[left.status] - STATUS_SORT_ORDER[right.status]),
    [referenceDate, statements],
  );
  const summary = useMemo(
    () => calculateBillingSummary(statements, referenceDate),
    [referenceDate, statements],
  );
  const normalizedQuery = query.trim().toLowerCase();
  const filteredStatements = useMemo(
    () =>
      statementViews.filter((statement) => {
        const matchesStatus = statusFilter === "all" || statement.status === statusFilter;
        const matchesQuery =
          !normalizedQuery ||
          [
            statement.id,
            statement.elderName,
            statement.roomLabel,
            statement.contactName,
            statement.contactPhone,
          ]
            .join(" ")
            .toLowerCase()
            .includes(normalizedQuery);
        return matchesStatus && matchesQuery;
      }),
    [normalizedQuery, statementViews, statusFilter],
  );
  const selectedStatement = dialog
    ? statementViews.find((statement) => statement.id === dialog.statementId)
    : undefined;

  function openPayment(statement: BillingStatementView): void {
    setMessage("");
    setDialog({
      kind: "payment",
      statementId: statement.id,
      form: {
        amountYuan: (statement.outstandingCents / 100).toFixed(2),
        method: "wechat",
        paidAt: toDateTimeInputValue(new Date()),
        reference: "",
        note: "",
      },
    });
  }

  function openCharge(statement: BillingStatementView): void {
    setMessage("");
    setDialog({
      kind: "charge",
      statementId: statement.id,
      form: {
        category: "护理服务",
        description: "",
        quantity: "1",
        serviceDate: toDateInputValue(new Date()),
        unitPriceYuan: "",
      },
    });
  }

  function updatePaymentForm(next: Partial<PaymentFormState>): void {
    setDialog((current) =>
      current?.kind === "payment" ? { ...current, form: { ...current.form, ...next } } : current,
    );
  }

  function updateChargeForm(next: Partial<ChargeFormState>): void {
    setDialog((current) =>
      current?.kind === "charge" ? { ...current, form: { ...current.form, ...next } } : current,
    );
  }

  function submitPayment(event: FormEvent<HTMLFormElement>): void {
    event.preventDefault();
    if (dialog?.kind !== "payment" || !selectedStatement) {
      return;
    }

    const amountCents = parseYuanToCents(dialog.form.amountYuan);
    if (!amountCents) {
      setMessage("请输入有效的收款金额");
      return;
    }
    if (amountCents > selectedStatement.outstandingCents) {
      setMessage(`收款金额不能超过待收金额 ${formatCny(selectedStatement.outstandingCents)}`);
      return;
    }

    const paidAt = new Date(dialog.form.paidAt);
    if (Number.isNaN(paidAt.getTime())) {
      setMessage("请选择有效的收款时间");
      return;
    }

    const statementId = selectedStatement.id;
    const payment = {
      id: `${statementId}-payment-${Date.now()}`,
      amountCents,
      method: dialog.form.method,
      paidAt: paidAt.toISOString(),
      reference: dialog.form.reference.trim() || `PAY${Date.now()}`,
      operator: "当前操作员",
      note: dialog.form.note.trim(),
    };
    setStatements((current) =>
      current.map((statement) =>
        statement.id === statementId ? addBillingPayment(statement, payment) : statement,
      ),
    );
    setDialog({ kind: "detail", statementId });
    setMessage(`${selectedStatement.elderName} 收款 ${formatCny(amountCents)} 已登记`);
  }

  function submitCharge(event: FormEvent<HTMLFormElement>): void {
    event.preventDefault();
    if (dialog?.kind !== "charge" || !selectedStatement) {
      return;
    }

    const quantity = Number(dialog.form.quantity);
    const unitPriceCents = parseYuanToCents(dialog.form.unitPriceYuan);
    if (!dialog.form.description.trim()) {
      setMessage("请输入费用项目说明");
      return;
    }
    if (!Number.isFinite(quantity) || quantity <= 0) {
      setMessage("请输入有效的数量");
      return;
    }
    if (!unitPriceCents) {
      setMessage("请输入有效的单价");
      return;
    }

    const serviceDate = new Date(`${dialog.form.serviceDate}T12:00:00`);
    if (Number.isNaN(serviceDate.getTime())) {
      setMessage("请选择有效的服务日期");
      return;
    }

    const statementId = selectedStatement.id;
    const charge: BillingCharge = {
      id: `${statementId}-charge-${Date.now()}`,
      category: dialog.form.category,
      description: dialog.form.description.trim(),
      quantity,
      serviceDate: serviceDate.toISOString(),
      unitPriceCents,
    };
    setStatements((current) =>
      current.map((statement) =>
        statement.id === statementId ? addBillingCharge(statement, charge) : statement,
      ),
    );
    setDialog({ kind: "detail", statementId });
    setMessage(`${selectedStatement.elderName} 新增费用 ${formatCny(Math.round(quantity * unitPriceCents))}`);
  }

  function generateReceipt(statement: BillingStatementView): void {
    if (statement.payments.length === 0 || statement.receiptCount >= statement.payments.length) {
      setMessage("当前收款记录均已生成收据");
      return;
    }
    setStatements((current) =>
      current.map((item) =>
        item.id === statement.id ? { ...item, receiptCount: item.payments.length } : item,
      ),
    );
    setMessage(`${statement.elderName} 的最新收款收据已生成`);
  }

  function issueInvoice(statement: BillingStatementView): void {
    if (statement.outstandingCents > 0) {
      setMessage("账单结清后才能开具发票");
      return;
    }
    if (statement.invoiceStatus === "issued") {
      setMessage(`发票 ${statement.invoiceNumber ?? ""} 已开具`);
      return;
    }

    const compactDate = new Date().toISOString().slice(0, 10).replaceAll("-", "");
    const invoiceNumber = `FP${compactDate}${statement.id.slice(-3).toUpperCase()}`;
    setStatements((current) =>
      current.map((item) =>
        item.id === statement.id ? { ...item, invoiceStatus: "issued", invoiceNumber } : item,
      ),
    );
    setMessage(`${statement.elderName} 的电子发票已开具：${invoiceNumber}`);
  }

  const dialogTitle =
    dialog?.kind === "payment" ? "登记收款" : dialog?.kind === "charge" ? "登记费用" : "账单详情";

  return (
    <div className="mx-auto flex w-full max-w-7xl flex-col gap-5">
      <section className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
        <MetricCard icon={CircleDollarSign} label="本月应收" value={formatCny(summary.receivableCents)} />
        <MetricCard icon={HandCoins} label="本月已收" value={formatCny(summary.collectedCents)} />
        <MetricCard icon={WalletCards} label="待收金额" value={formatCny(summary.outstandingCents)} />
        <MetricCard icon={TriangleAlert} label="逾期账户" value={`${summary.overdueCount} 户`} tone="danger" />
      </section>

      <section className="flex flex-col gap-4 border-b pb-5 lg:flex-row lg:items-end lg:justify-between">
        <div>
          <h1 className="text-3xl font-semibold tracking-normal">费用管理</h1>
          <p className="mt-2 text-sm text-muted-foreground">统一查看老人月度账单、费用项目、收款记录和票据状态。</p>
        </div>
        <div className="grid w-full gap-2 sm:grid-cols-2 lg:w-auto lg:min-w-[34rem]">
          <label className="relative block">
            <Search className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
            <Input
              aria-label="搜索费用账单"
              className="pl-9"
              onChange={(event) => setQuery(event.target.value)}
              placeholder="搜索老人、房间、联系人或账单号"
              value={query}
            />
          </label>
          <Select
            aria-label="账单状态"
            onValueChange={(value) => setStatusFilter(value as "all" | BillingStatus)}
            options={[
              { value: "all", label: "全部账单状态" },
              ...BILLING_STATUS_VALUES.map((status) => ({ value: status, label: BILLING_STATUS_LABELS[status] })),
            ]}
            value={statusFilter}
          />
        </div>
      </section>

      {message ? (
        <p className="rounded-md bg-secondary px-3 py-2 text-sm text-secondary-foreground" role="status">
          {message}
        </p>
      ) : null}

      <Card>
        <CardHeader className="gap-1">
          <CardTitle>月度账单</CardTitle>
          <CardDescription>当前显示 {filteredStatements.length} 条账单。</CardDescription>
        </CardHeader>
        <CardContent className="overflow-x-auto">
          <Table className="w-full min-w-[1040px] text-sm">
            <Table.Header className="bg-secondary text-left text-xs text-muted-foreground">
              <Table.Row>
                <Table.Head className="px-4 py-3">老人 / 账期</Table.Head>
                <Table.Head className="px-4 py-3">房间床位</Table.Head>
                <Table.Head className="px-4 py-3">应收金额</Table.Head>
                <Table.Head className="px-4 py-3">已收金额</Table.Head>
                <Table.Head className="px-4 py-3">待收金额</Table.Head>
                <Table.Head className="px-4 py-3">到期日</Table.Head>
                <Table.Head className="px-4 py-3">状态</Table.Head>
                <Table.Head className="px-4 py-3">票据</Table.Head>
                <Table.Head className="px-4 py-3 text-right">操作</Table.Head>
              </Table.Row>
            </Table.Header>
            <Table.Body className="divide-y bg-card">
              {filteredStatements.map((statement) => (
                <Table.Row key={statement.id}>
                  <Table.Cell className="px-4 py-3">
                    <p className="font-medium">{statement.elderName}</p>
                    <p className="text-xs text-muted-foreground">
                      {formatBillingPeriod(statement.period)} / {statement.id.toUpperCase()}
                    </p>
                  </Table.Cell>
                  <Table.Cell className="px-4 py-3 text-muted-foreground">{statement.roomLabel}</Table.Cell>
                  <Table.Cell className="px-4 py-3 font-medium tabular-nums">{formatCny(statement.totalCents)}</Table.Cell>
                  <Table.Cell className="px-4 py-3 tabular-nums text-muted-foreground">{formatCny(statement.paidCents)}</Table.Cell>
                  <Table.Cell className="px-4 py-3 font-medium tabular-nums">{formatCny(statement.outstandingCents)}</Table.Cell>
                  <Table.Cell className="px-4 py-3 text-muted-foreground">{formatDate(statement.dueAt)}</Table.Cell>
                  <Table.Cell className="px-4 py-3">
                    <Badge variant={getStatusVariant(statement.status)}>{BILLING_STATUS_LABELS[statement.status]}</Badge>
                  </Table.Cell>
                  <Table.Cell className="px-4 py-3">
                    <Badge variant={getInvoiceVariant(statement.invoiceStatus)}>
                      {INVOICE_STATUS_LABELS[statement.invoiceStatus]}
                    </Badge>
                  </Table.Cell>
                  <Table.Cell className="px-4 py-3">
                    <div className="flex justify-end gap-2">
                      <Button
                        aria-label={`查看 ${statement.elderName} 账单`}
                        onClick={() => setDialog({ kind: "detail", statementId: statement.id })}
                        size="icon"
                        title="查看账单"
                        type="button"
                        variant="outline"
                      >
                        <Eye className="size-4" aria-hidden="true" />
                      </Button>
                      <Button
                        aria-label={`登记 ${statement.elderName} 费用`}
                        onClick={() => openCharge(statement)}
                        size="icon"
                        title="登记费用"
                        type="button"
                        variant="outline"
                      >
                        <Plus className="size-4" aria-hidden="true" />
                      </Button>
                      <Button
                        aria-label={`登记 ${statement.elderName} 收款`}
                        disabled={statement.outstandingCents === 0}
                        onClick={() => openPayment(statement)}
                        size="icon"
                        title="登记收款"
                        type="button"
                      >
                        <Banknote className="size-4" aria-hidden="true" />
                      </Button>
                    </div>
                  </Table.Cell>
                </Table.Row>
              ))}
              {filteredStatements.length === 0 ? (
                <Table.Row>
                  <Table.Cell className="px-4 py-10 text-center text-muted-foreground" colSpan={9}>
                    暂无匹配账单
                  </Table.Cell>
                </Table.Row>
              ) : null}
            </Table.Body>
          </Table>
        </CardContent>
      </Card>

      <Dialog
        description={selectedStatement ? `${selectedStatement.elderName} / ${formatBillingPeriod(selectedStatement.period)}` : undefined}
        onClose={() => setDialog(undefined)}
        open={dialog !== undefined && selectedStatement !== undefined}
        title={dialogTitle}
        width={dialog?.kind === "detail" ? "wide" : "lg"}
      >
        {dialog?.kind === "detail" && selectedStatement ? (
          <StatementDetail
            onCharge={() => openCharge(selectedStatement)}
            onInvoice={() => issueInvoice(selectedStatement)}
            onPayment={() => openPayment(selectedStatement)}
            onReceipt={() => generateReceipt(selectedStatement)}
            statement={selectedStatement}
          />
        ) : null}
        {dialog?.kind === "payment" && selectedStatement ? (
          <PaymentForm
            form={dialog.form}
            onCancel={() => setDialog({ kind: "detail", statementId: selectedStatement.id })}
            onSubmit={submitPayment}
            onUpdate={updatePaymentForm}
            statement={selectedStatement}
          />
        ) : null}
        {dialog?.kind === "charge" && selectedStatement ? (
          <ChargeForm
            form={dialog.form}
            onCancel={() => setDialog({ kind: "detail", statementId: selectedStatement.id })}
            onSubmit={submitCharge}
            onUpdate={updateChargeForm}
          />
        ) : null}
      </Dialog>
    </div>
  );
}

function StatementDetail({
  onCharge,
  onInvoice,
  onPayment,
  onReceipt,
  statement,
}: {
  onCharge: () => void;
  onInvoice: () => void;
  onPayment: () => void;
  onReceipt: () => void;
  statement: BillingStatementView;
}): React.ReactElement {
  const canGenerateReceipt = statement.payments.length > statement.receiptCount;
  const canIssueInvoice = statement.outstandingCents === 0 && statement.invoiceStatus !== "issued";

  return (
    <div className="grid gap-5">
      <section className="grid gap-4 border-b pb-5 sm:grid-cols-2 lg:grid-cols-4">
        <SummaryItem label="应收金额" value={formatCny(statement.totalCents)} />
        <SummaryItem label="已收金额" value={formatCny(statement.paidCents)} />
        <SummaryItem label="待收金额" value={formatCny(statement.outstandingCents)} />
        <div>
          <p className="text-xs text-muted-foreground">账单状态</p>
          <Badge className="mt-2" variant={getStatusVariant(statement.status)}>
            {BILLING_STATUS_LABELS[statement.status]}
          </Badge>
        </div>
      </section>

      <section className="grid gap-3 rounded-md border bg-secondary/25 p-4 sm:grid-cols-2 lg:grid-cols-4">
        <InfoItem label="房间床位" value={statement.roomLabel} />
        <InfoItem label="缴费联系人" value={statement.contactName} />
        <InfoItem label="联系电话" value={statement.contactPhone} />
        <InfoItem label="到期日期" value={formatDate(statement.dueAt)} />
      </section>

      <section className="grid gap-2">
        <div className="flex items-center justify-between gap-3">
          <h3 className="text-sm font-semibold">费用明细</h3>
          <Button onClick={onCharge} size="sm" type="button" variant="outline">
            <FilePlus2 className="size-4" aria-hidden="true" />
            登记费用
          </Button>
        </div>
        <div className="overflow-x-auto rounded-md border">
          <Table className="w-full min-w-[720px] text-sm">
            <Table.Header className="bg-secondary text-left text-xs text-muted-foreground">
              <Table.Row>
                <Table.Head className="px-4 py-3">费用项目</Table.Head>
                <Table.Head className="px-4 py-3">服务日期</Table.Head>
                <Table.Head className="px-4 py-3">数量</Table.Head>
                <Table.Head className="px-4 py-3">单价</Table.Head>
                <Table.Head className="px-4 py-3 text-right">金额</Table.Head>
              </Table.Row>
            </Table.Header>
            <Table.Body className="divide-y bg-card">
              {statement.charges.map((charge) => (
                <Table.Row key={charge.id}>
                  <Table.Cell className="px-4 py-3">
                    <p className="font-medium">{charge.description}</p>
                    <p className="text-xs text-muted-foreground">{charge.category}</p>
                  </Table.Cell>
                  <Table.Cell className="px-4 py-3 text-muted-foreground">{formatDate(charge.serviceDate)}</Table.Cell>
                  <Table.Cell className="px-4 py-3 tabular-nums">{charge.quantity}</Table.Cell>
                  <Table.Cell className="px-4 py-3 tabular-nums">{formatCny(charge.unitPriceCents)}</Table.Cell>
                  <Table.Cell className="px-4 py-3 text-right font-medium tabular-nums">
                    {formatCny(Math.round(charge.quantity * charge.unitPriceCents))}
                  </Table.Cell>
                </Table.Row>
              ))}
            </Table.Body>
          </Table>
        </div>
      </section>

      <section className="grid gap-2">
        <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
          <div>
            <h3 className="text-sm font-semibold">收款与票据</h3>
            <p className="mt-1 text-xs text-muted-foreground">
              收据 {statement.receiptCount}/{statement.payments.length} · {INVOICE_STATUS_LABELS[statement.invoiceStatus]}
              {statement.invoiceNumber ? ` / ${statement.invoiceNumber}` : ""}
            </p>
          </div>
          <div className="flex flex-wrap gap-2">
            <Button disabled={statement.outstandingCents === 0} onClick={onPayment} size="sm" type="button">
              <Banknote className="size-4" aria-hidden="true" />
              登记收款
            </Button>
            <Button disabled={!canGenerateReceipt} onClick={onReceipt} size="sm" type="button" variant="outline">
              <ReceiptText className="size-4" aria-hidden="true" />
              生成收据
            </Button>
            <Button disabled={!canIssueInvoice} onClick={onInvoice} size="sm" type="button" variant="outline">
              <FileText className="size-4" aria-hidden="true" />
              {statement.invoiceStatus === "issued" ? "发票已开具" : "开具发票"}
            </Button>
          </div>
        </div>
        <div className="overflow-x-auto rounded-md border">
          <Table className="w-full min-w-[760px] text-sm">
            <Table.Header className="bg-secondary text-left text-xs text-muted-foreground">
              <Table.Row>
                <Table.Head className="px-4 py-3">收款时间</Table.Head>
                <Table.Head className="px-4 py-3">方式</Table.Head>
                <Table.Head className="px-4 py-3">流水号</Table.Head>
                <Table.Head className="px-4 py-3">经办人</Table.Head>
                <Table.Head className="px-4 py-3">收据</Table.Head>
                <Table.Head className="px-4 py-3 text-right">金额</Table.Head>
              </Table.Row>
            </Table.Header>
            <Table.Body className="divide-y bg-card">
              {statement.payments.map((payment, index) => (
                <Table.Row key={payment.id}>
                  <Table.Cell className="px-4 py-3 text-muted-foreground">{formatDateTime(payment.paidAt)}</Table.Cell>
                  <Table.Cell className="px-4 py-3">{PAYMENT_METHOD_LABELS[payment.method]}</Table.Cell>
                  <Table.Cell className="px-4 py-3 text-muted-foreground">{payment.reference}</Table.Cell>
                  <Table.Cell className="px-4 py-3 text-muted-foreground">{payment.operator}</Table.Cell>
                  <Table.Cell className="px-4 py-3">
                    <Badge variant={index < statement.receiptCount ? "success" : "secondary"}>
                      {index < statement.receiptCount ? "已生成" : "待生成"}
                    </Badge>
                  </Table.Cell>
                  <Table.Cell className="px-4 py-3 text-right font-medium tabular-nums">{formatCny(payment.amountCents)}</Table.Cell>
                </Table.Row>
              ))}
              {statement.payments.length === 0 ? (
                <Table.Row>
                  <Table.Cell className="px-4 py-8 text-center text-muted-foreground" colSpan={6}>
                    暂无收款记录
                  </Table.Cell>
                </Table.Row>
              ) : null}
            </Table.Body>
          </Table>
        </div>
      </section>
    </div>
  );
}

function PaymentForm({
  form,
  onCancel,
  onSubmit,
  onUpdate,
  statement,
}: {
  form: PaymentFormState;
  onCancel: () => void;
  onSubmit: (event: FormEvent<HTMLFormElement>) => void;
  onUpdate: (next: Partial<PaymentFormState>) => void;
  statement: BillingStatementView;
}): React.ReactElement {
  return (
    <form className="grid gap-4" onSubmit={onSubmit}>
      <div className="rounded-md border bg-secondary/25 p-4">
        <p className="text-sm text-muted-foreground">当前待收</p>
        <p className="mt-1 text-2xl font-semibold tabular-nums">{formatCny(statement.outstandingCents)}</p>
      </div>
      <div className="grid gap-3 sm:grid-cols-2">
        <Input
          label="收款金额（元）"
          max={(statement.outstandingCents / 100).toFixed(2)}
          min="0.01"
          onChange={(event) => onUpdate({ amountYuan: event.target.value })}
          required
          step="0.01"
          type="number"
          value={form.amountYuan}
        />
        <Select
          label="收款方式"
          onValueChange={(value) => onUpdate({ method: value as PaymentMethod })}
          options={PAYMENT_METHOD_VALUES.map((method) => ({ value: method, label: PAYMENT_METHOD_LABELS[method] }))}
          value={form.method}
        />
        <Input
          label="收款时间"
          onChange={(event) => onUpdate({ paidAt: event.target.value })}
          required
          type="datetime-local"
          value={form.paidAt}
        />
        <Input
          label="支付流水号"
          onChange={(event) => onUpdate({ reference: event.target.value })}
          placeholder="留空后自动生成"
          value={form.reference}
        />
      </div>
      <Textarea
        label="备注"
        onChange={(event) => onUpdate({ note: event.target.value })}
        placeholder="填写付款人或对账说明"
        value={form.note}
      />
      <div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
        <Button onClick={onCancel} type="button" variant="outline">取消</Button>
        <Button type="submit">
          <Banknote className="size-4" aria-hidden="true" />
          确认收款
        </Button>
      </div>
    </form>
  );
}

function ChargeForm({
  form,
  onCancel,
  onSubmit,
  onUpdate,
}: {
  form: ChargeFormState;
  onCancel: () => void;
  onSubmit: (event: FormEvent<HTMLFormElement>) => void;
  onUpdate: (next: Partial<ChargeFormState>) => void;
}): React.ReactElement {
  return (
    <form className="grid gap-4" onSubmit={onSubmit}>
      <div className="grid gap-3 sm:grid-cols-2">
        <Select
          label="费用分类"
          onValueChange={(value) => onUpdate({ category: value })}
          options={chargeCategoryOptions}
          value={form.category}
        />
        <Input
          label="服务日期"
          onChange={(event) => onUpdate({ serviceDate: event.target.value })}
          required
          type="date"
          value={form.serviceDate}
        />
      </div>
      <Input
        label="费用项目说明"
        onChange={(event) => onUpdate({ description: event.target.value })}
        placeholder="例如：临时陪诊服务"
        required
        value={form.description}
      />
      <div className="grid gap-3 sm:grid-cols-2">
        <Input
          label="数量"
          min="0.01"
          onChange={(event) => onUpdate({ quantity: event.target.value })}
          required
          step="0.01"
          type="number"
          value={form.quantity}
        />
        <Input
          label="单价（元）"
          min="0.01"
          onChange={(event) => onUpdate({ unitPriceYuan: event.target.value })}
          required
          step="0.01"
          type="number"
          value={form.unitPriceYuan}
        />
      </div>
      <div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
        <Button onClick={onCancel} type="button" variant="outline">取消</Button>
        <Button type="submit">
          <Plus className="size-4" aria-hidden="true" />
          确认登记
        </Button>
      </div>
    </form>
  );
}

function MetricCard({
  icon: Icon,
  label,
  tone = "default",
  value,
}: {
  icon: React.ComponentType<{ "aria-hidden"?: boolean; className?: string }>;
  label: string;
  tone?: "danger" | "default";
  value: string;
}): React.ReactElement {
  return (
    <Card>
      <CardHeader className="flex flex-row items-center justify-between gap-3 p-4">
        <div className="min-w-0">
          <p className="text-sm text-muted-foreground">{label}</p>
          <CardTitle className="mt-2 truncate text-2xl tabular-nums">{value}</CardTitle>
        </div>
        <Icon className={tone === "danger" ? "size-5 shrink-0 text-destructive" : "size-5 shrink-0 text-primary"} aria-hidden={true} />
      </CardHeader>
    </Card>
  );
}

function SummaryItem({ label, value }: { label: string; value: string }): React.ReactElement {
  return (
    <div>
      <p className="text-xs text-muted-foreground">{label}</p>
      <p className="mt-1 text-xl font-semibold tabular-nums">{value}</p>
    </div>
  );
}

function InfoItem({ label, value }: { label: string; value: string }): React.ReactElement {
  return (
    <div className="min-w-0">
      <p className="text-xs text-muted-foreground">{label}</p>
      <p className="mt-1 truncate text-sm font-medium">{value}</p>
    </div>
  );
}
