import { useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import type { TFunction } from 'i18next';
import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts';
import { Button } from '../../components/ui/Button';
import { EmptyState, ErrorState, Skeleton } from '../../components/ui/States';
import { IconAnalytics, IconDocument, IconPie } from '../../components/ui/icons';
import { CHART } from '../chartColors';
import { useResolvedEventId } from '../../hooks/useResolvedEventId';
import { useAuthStore } from '../../store/authStore';
import { settlementApi } from './settlementApi';
import type { InvoiceCategory, InvoiceStatus, ReportGroup, StatusBucket } from './settlementApi';
import './settlement.css';

/*
 * SCR /settlement — M9 정산·결제 현황 대시보드.
 * GET /api/settlement/dashboard (청구/수납/미수 KPI + 상태 분포),
 * GET /api/settlement/invoices (상태 필터·페이지네이션), 상세(라인아이템+수납 이력),
 * 수납 기록·발행·청구 생성(매니저 이상 — 서버 재검증).
 * 금액은 모두 서버 계산 권위. 결제는 PG 위임 고지 — 실 PG 연동 없이 상태만 전이.
 */

const PAGE_SIZE = 20;

const STATUS_META: Record<InvoiceStatus, { color: string; tone: string }> = {
  pending: { color: CHART.slate, tone: 'muted' },
  invoiced: { color: CHART.primary600, tone: 'info' },
  paid: { color: CHART.success, tone: 'ok' },
  overdue: { color: CHART.error, tone: 'error' },
  cancelled: { color: CHART.slate, tone: 'muted' },
};

const STATUS_FILTER_VALUES: Array<'' | InvoiceStatus> = ['', 'pending', 'invoiced', 'paid', 'overdue', 'cancelled'];

/** 청구 상태 → 현지화 라벨. '' 은 전체 필터. */
function statusLabel(t: TFunction, status: '' | InvoiceStatus): string {
  return status === '' ? t('settlement.status.all') : t(`settlement.status.${status}`);
}

export function SettlementDashboardPage() {
  const { t } = useTranslation();
  const eventId = useResolvedEventId();
  const role = useAuthStore((s) => s.roleForCurrent());
  const canManage = role === 'ORGANIZER' || role === 'HALL_MANAGER';

  const [statusFilter, setStatusFilter] = useState<'' | InvoiceStatus>('');
  const [page, setPage] = useState(0);
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const qc = useQueryClient();

  const dashboardQ = useQuery({
    queryKey: ['settlement', 'dashboard', eventId],
    queryFn: () => settlementApi.dashboard(eventId as string),
    enabled: !!eventId,
    retry: false,
  });

  const listQ = useQuery({
    queryKey: ['settlement', 'invoices', eventId, statusFilter, page],
    queryFn: () => settlementApi.invoices(eventId as string, statusFilter || null, page, PAGE_SIZE),
    enabled: !!eventId,
    retry: false,
  });

  const generateM = useMutation({
    mutationFn: () => settlementApi.generate(eventId as string),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['settlement'] });
    },
  });

  const refetchAll = () => {
    qc.invalidateQueries({ queryKey: ['settlement'] });
  };

  if (!eventId) {
    return (
      <div className="kx-settle">
        <PageHeader canManage={false} onGenerate={() => {}} generating={false} />
        <EmptyState title={t('settlement.noEventTitle')} description={t('settlement.noEventDesc')} />
      </div>
    );
  }

  const dash = dashboardQ.data;
  const list = listQ.data;
  const totalPages = list ? Math.max(1, Math.ceil(list.total / PAGE_SIZE)) : 1;

  return (
    <div className="kx-settle">
      <PageHeader
        canManage={canManage}
        onGenerate={() => generateM.mutate()}
        generating={generateM.isPending}
      />

      {generateM.isSuccess && generateM.data && (
        <div className="kx-settle__notice" role="status">
          {t('settlement.genDone', { created: generateM.data.created, skipped: generateM.data.skipped })}
        </div>
      )}
      {generateM.isError && (
        <div className="kx-settle__notice kx-settle__notice--error" role="alert">
          {t('settlement.genError')}
        </div>
      )}

      {/* KPI 밴드 */}
      {dashboardQ.isLoading ? (
        <div className="kx-settle__kpis" aria-hidden="true">
          {[0, 1, 2, 3].map((i) => (
            <Skeleton key={i} height={92} radius={12} />
          ))}
        </div>
      ) : dashboardQ.isError ? (
        <ErrorState message={t('settlement.dashError')} onRetry={() => dashboardQ.refetch()} />
      ) : dash ? (
        <>
          <section className="kx-settle__kpis" aria-label={t('settlement.kpisAria')}>
            <KpiCard label={t('settlement.kpiBilled')} value={formatWon(dash.billed)} tone="info" sub={t('settlement.count', { n: dash.invoiceCount })} />
            <KpiCard
              label={t('settlement.kpiCollected')}
              value={formatWon(dash.collected)}
              tone="ok"
              sub={t('settlement.collectionRate', { rate: dash.collectionRate.toFixed(1) })}
            />
            <KpiCard label={t('settlement.kpiOutstanding')} value={formatWon(dash.outstanding)} tone="muted" sub={t('settlement.outstandingSub')} />
            <KpiCard
              label={t('settlement.kpiOverdue')}
              value={t('settlement.count', { n: dash.overdueCount })}
              tone={dash.overdueCount > 0 ? 'error' : 'muted'}
              sub={t('settlement.overdueSub')}
            />
          </section>

          {/* 상태 분포 도넛 + 범례 */}
          <section className="kx-card kx-settle__dist" aria-label={t('settlement.distTitle')}>
            <div className="kx-card__head">
              <h2><IconPie className="kx-title-ic" size={18} />{t('settlement.distTitle')}</h2>
            </div>
            <StatusDistribution buckets={dash.statusDistribution} />
            <p className="kx-settle__paynote">{dash.paymentNote}</p>
          </section>
        </>
      ) : null}

      {/* 청구서 목록 */}
      <section className="kx-card kx-settle__list-card" aria-label={t('settlement.listTitle')}>
        <div className="kx-card__head kx-settle__list-head">
          <h2><IconDocument className="kx-title-ic" size={18} />{t('settlement.invoices')}</h2>
          <div className="kx-seg" role="tablist" aria-label={t('settlement.statusFilter')}>
            {STATUS_FILTER_VALUES.map((v) => (
              <button
                key={v || 'all'}
                role="tab"
                aria-selected={statusFilter === v}
                className={`kx-seg__btn ${statusFilter === v ? 'is-active' : ''}`}
                onClick={() => {
                  setStatusFilter(v);
                  setPage(0);
                }}
              >
                {statusLabel(t, v)}
              </button>
            ))}
          </div>
        </div>

        {listQ.isLoading ? (
          <div style={{ display: 'grid', gap: 8 }} aria-hidden="true">
            {[0, 1, 2, 3, 4].map((i) => (
              <Skeleton key={i} height={44} radius={8} />
            ))}
          </div>
        ) : listQ.isError ? (
          <ErrorState message={t('settlement.listError')} onRetry={() => listQ.refetch()} />
        ) : !list || list.items.length === 0 ? (
          <EmptyState
            title={t('settlement.emptyTitle')}
            description={canManage ? t('settlement.emptyManage') : t('settlement.emptyView')}
          />
        ) : (
          <>
            <div className="kx-table-scroll">
              <table className="kx-table kx-table--zebra">
                <thead>
                  <tr>
                    <th>{t('settlement.colNo')}</th>
                    <th>{t('settlement.colExhibitor')}</th>
                    <th className="kx-num">{t('settlement.colBilled')}</th>
                    <th className="kx-num">{t('settlement.colPaid')}</th>
                    <th className="kx-num">{t('settlement.colOutstanding')}</th>
                    <th>{t('settlement.colDue')}</th>
                    <th>{t('settlement.colStatus')}</th>
                    <th aria-label={t('settlement.detail')} />
                  </tr>
                </thead>
                <tbody>
                  {list.items.map((inv) => (
                    <tr key={inv.id} className="kx-settle__row" onClick={() => setSelectedId(inv.id)}>
                      <td className="tnum">{inv.invoiceNo}</td>
                      <td>
                        {inv.exhibitorName}
                        <CategoryTag category={inv.category} />
                      </td>
                      <td className="kx-num tnum">{formatWon(inv.total)}</td>
                      <td className="kx-num tnum">{formatWon(inv.paidAmount)}</td>
                      <td className="kx-num tnum">{formatWon(inv.outstanding)}</td>
                      <td>{inv.dueDate ?? '-'}</td>
                      <td>
                        <StatusPill status={inv.status} />
                      </td>
                      <td>
                        <button
                          className="kx-settle__link"
                          onClick={(e) => {
                            e.stopPropagation();
                            setSelectedId(inv.id);
                          }}
                        >
                          {t('settlement.detail')}
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
            <div className="kx-settle__pager">
              <Button
                variant="secondary"
                disabled={page <= 0}
                onClick={() => setPage((p) => Math.max(0, p - 1))}
              >
                {t('settlement.prev')}
              </Button>
              <span className="kx-settle__pageinfo tnum">
                {t('settlement.pageInfo', { page: page + 1, total: totalPages, cnt: list.total })}
              </span>
              <Button
                variant="secondary"
                disabled={page + 1 >= totalPages}
                onClick={() => setPage((p) => p + 1)}
              >
                {t('settlement.next')}
              </Button>
            </div>
          </>
        )}
      </section>

      {/* 정산 리포트(카테고리별 합계·수납율·미수 + CSV) */}
      <ReportSection eventId={eventId} />

      {selectedId && (
        <InvoiceDetailModal
          invoiceId={selectedId}
          onClose={() => setSelectedId(null)}
          onChanged={refetchAll}
        />
      )}
    </div>
  );
}

// ── 정산 리포트 섹션(F083) ────────────────────────────────────────────────────
function ReportSection({ eventId }: { eventId: string }) {
  const { t } = useTranslation();
  const [open, setOpen] = useState(false);

  const reportQ = useQuery({
    queryKey: ['settlement', 'report', eventId],
    queryFn: () => settlementApi.report(eventId),
    enabled: open && !!eventId,
    retry: false,
  });

  const rep = reportQ.data;

  const downloadCsv = () => {
    if (!rep) return;
    const header = [
      t('settlement.colNo'),
      t('settlement.colExhibitor'),
      t('settlement.colCategory'),
      t('settlement.colStatus'),
      t('settlement.supplyAmount'),
      t('settlement.vat'),
      t('settlement.colBilled'),
      t('settlement.colPaid'),
      t('settlement.colOutstanding'),
      t('settlement.colDue'),
    ];
    const lines = rep.rows.map((r) =>
      [
        r.invoiceNo,
        r.exhibitorName,
        r.category,
        r.status,
        r.subtotal,
        r.vat,
        r.total,
        r.paidAmount,
        r.outstanding,
        r.dueDate ?? '',
      ]
        .map(csvCell)
        .join(','),
    );
    const csv = '﻿' + [header.map(csvCell).join(','), ...lines].join('\r\n');
    const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `settlement_report_${eventId}.csv`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  return (
    <section className="kx-card kx-settle__report" aria-label={t('settlement.reportTitle')}>
      <div className="kx-card__head kx-settle__report-head">
        <h2><IconAnalytics className="kx-title-ic" size={18} />{t('settlement.reportTitle')}</h2>
        <div className="kx-settle__report-actions">
          <Button variant="secondary" onClick={() => setOpen((v) => !v)}>
            {open ? t('settlement.reportHide') : t('settlement.reportShow')}
          </Button>
          {open && rep && (
            <Button variant="primary" onClick={downloadCsv} disabled={rep.rows.length === 0}>
              {t('settlement.reportCsv')}
            </Button>
          )}
        </div>
      </div>

      {!open ? (
        <p className="kx-settle__muted">{t('settlement.reportHint')}</p>
      ) : reportQ.isLoading ? (
        <div style={{ display: 'grid', gap: 8 }} aria-hidden="true">
          {[0, 1, 2].map((i) => (
            <Skeleton key={i} height={40} radius={8} />
          ))}
        </div>
      ) : reportQ.isError || !rep ? (
        <ErrorState message={t('settlement.reportError')} onRetry={() => reportQ.refetch()} />
      ) : (
        <div className="kx-settle__report-body">
          <div className="kx-settle__report-summary">
            <span>
              {t('settlement.colBilled')}: <strong className="tnum">{formatWon(rep.totalBilled)}</strong>
            </span>
            <span>
              {t('settlement.colPaid')}: <strong className="tnum">{formatWon(rep.totalCollected)}</strong>
            </span>
            <span>
              {t('settlement.colOutstanding')}: <strong className="tnum">{formatWon(rep.totalOutstanding)}</strong>
            </span>
            <span>
              {t('settlement.collectionRate', { rate: rep.collectionRate.toFixed(1) })}
            </span>
          </div>
          <ReportGroupTable title={t('settlement.reportByCategory')} groups={rep.byCategory} category />
          <ReportGroupTable title={t('settlement.reportByStatus')} groups={rep.byStatus} />
          <p className="kx-settle__muted">{t('settlement.reportNote')}</p>
        </div>
      )}
    </section>
  );
}

function ReportGroupTable({ title, groups, category }: { title: string; groups: ReportGroup[]; category?: boolean }) {
  const { t } = useTranslation();
  return (
    <div className="kx-settle__report-group">
      <h3>{title}</h3>
      {groups.length === 0 ? (
        <p className="kx-settle__muted">{t('settlement.reportEmpty')}</p>
      ) : (
        <table className="kx-table kx-table--zebra">
          <thead>
            <tr>
              <th>{category ? t('settlement.colCategory') : t('settlement.colStatus')}</th>
              <th className="kx-num">{t('settlement.reportCount')}</th>
              <th className="kx-num">{t('settlement.colBilled')}</th>
              <th className="kx-num">{t('settlement.colPaid')}</th>
              <th className="kx-num">{t('settlement.colOutstanding')}</th>
              <th className="kx-num">{t('settlement.reportRate')}</th>
            </tr>
          </thead>
          <tbody>
            {groups.map((g) => (
              <tr key={g.key}>
                <td>{groupLabel(t, g.key, category)}</td>
                <td className="kx-num tnum">{g.invoiceCount.toLocaleString()}</td>
                <td className="kx-num tnum">{g.billed.toLocaleString()}</td>
                <td className="kx-num tnum">{g.collected.toLocaleString()}</td>
                <td className="kx-num tnum">{g.outstanding.toLocaleString()}</td>
                <td className="kx-num tnum">{g.collectionRate.toFixed(1)}%</td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
    </div>
  );
}

function groupLabel(t: TFunction, key: string, category?: boolean): string {
  if (category) {
    return key === 'auction_fee' ? t('settlement.catAuctionFee') : t('settlement.catRental');
  }
  const known: InvoiceStatus[] = ['pending', 'invoiced', 'paid', 'overdue', 'cancelled'];
  return (known as string[]).includes(key) ? t(`settlement.status.${key}`) : key;
}

/** CSV 셀 이스케이프(쉼표·따옴표·줄바꿈 방어). */
function csvCell(v: string | number): string {
  const s = String(v ?? '');
  return /[",\r\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
}

// ── 헤더 ─────────────────────────────────────────────────────────────────────
function PageHeader({
  canManage,
  onGenerate,
  generating,
}: {
  canManage: boolean;
  onGenerate: () => void;
  generating: boolean;
}) {
  const { t } = useTranslation();
  return (
    <header className="kx-settle__head">
      <div>
        <h1 className="kx-settle__title">{t('settlement.title')}</h1>
        <p className="kx-settle__subtitle">{t('settlement.subtitle')}</p>
      </div>
      {canManage && (
        <div className="kx-settle__head-actions">
          <Button variant="primary" onClick={onGenerate} disabled={generating}>
            {generating ? t('settlement.generating') : t('settlement.generate')}
          </Button>
        </div>
      )}
    </header>
  );
}

// ── KPI 카드 ─────────────────────────────────────────────────────────────────
function KpiCard({
  label,
  value,
  sub,
  tone,
}: {
  label: string;
  value: string;
  sub?: string;
  tone: 'info' | 'ok' | 'error' | 'muted';
}) {
  return (
    <div className={`kx-kpi kx-settle__kpi kx-settle__kpi--${tone}`}>
      <span className="kx-kpi__label">{label}</span>
      <strong className="kx-kpi__value tnum">{value}</strong>
      {sub && <span className="kx-settle__kpi-sub">{sub}</span>}
    </div>
  );
}

// ── 상태 분포(도넛) ───────────────────────────────────────────────────────────
function StatusDistribution({ buckets }: { buckets: StatusBucket[] }) {
  const { t } = useTranslation();
  const data = useMemo(
    () =>
      buckets
        .filter((b) => b.count > 0)
        .map((b) => ({
          key: b.status,
          name: statusLabel(t, b.status),
          value: b.totalAmount,
          count: b.count,
          color: STATUS_META[b.status]?.color ?? CHART.slate,
        })),
    [buckets, t],
  );

  if (data.length === 0) {
    return <EmptyState title={t('settlement.distEmpty')} />;
  }

  return (
    <div className="kx-settle__dist-body">
      <div className="kx-settle__donut">
        <ResponsiveContainer width="100%" height={220}>
          <PieChart>
            <Pie data={data} dataKey="value" nameKey="name" innerRadius={58} outerRadius={88} paddingAngle={2}>
              {data.map((d) => (
                <Cell key={d.key} fill={d.color} />
              ))}
            </Pie>
            <Tooltip
              contentStyle={TOOLTIP_STYLE}
              formatter={(value, _name, item) => {
                const p = (item?.payload ?? {}) as { count?: number; name?: string };
                return [`${formatWon(Number(value))} · ${t('settlement.count', { n: p.count ?? 0 })}`, p.name ?? ''];
              }}
            />
          </PieChart>
        </ResponsiveContainer>
      </div>
      <ul className="kx-settle__legend">
        {data.map((d) => (
          <li key={d.key} className="kx-settle__legend-item">
            <span className="kx-settle__legend-dot" style={{ background: d.color }} aria-hidden="true" />
            <span className="kx-settle__legend-name">{d.name}</span>
            <span className="kx-settle__legend-val tnum">
              {t('settlement.count', { n: d.count })} · {formatWon(d.value)}
            </span>
          </li>
        ))}
      </ul>
    </div>
  );
}

// ── 유형 표시(F084 옥션 수수료 구분) ─────────────────────────────────────────
function CategoryTag({ category }: { category: InvoiceCategory }) {
  const { t } = useTranslation();
  const label = category === 'auction_fee' ? t('settlement.catAuctionFee') : t('settlement.catRental');
  return <span className={`kx-settle__cattag kx-settle__cattag--${category}`}>{label}</span>;
}

// ── 상태 표시 ─────────────────────────────────────────────────────────────────
function StatusPill({ status }: { status: InvoiceStatus }) {
  const { t } = useTranslation();
  const meta = STATUS_META[status] ?? { tone: 'muted', color: CHART.slate };
  return <span className={`kx-settle__pill kx-settle__pill--${meta.tone}`}>{statusLabel(t, status)}</span>;
}

// ── 상세 모달(라인아이템 + 수납 이력 + 수납 기록) ─────────────────────────────
function InvoiceDetailModal({
  invoiceId,
  onClose,
  onChanged,
}: {
  invoiceId: string;
  onClose: () => void;
  onChanged: () => void;
}) {
  const { t } = useTranslation();
  const qc = useQueryClient();
  const [amount, setAmount] = useState('');
  const [method, setMethod] = useState<'manual' | 'transfer' | 'card'>('transfer');
  const [memo, setMemo] = useState('');
  const [formError, setFormError] = useState<string | null>(null);

  const detailQ = useQuery({
    queryKey: ['settlement', 'detail', invoiceId],
    queryFn: () => settlementApi.detail(invoiceId),
    retry: false,
  });

  const invalidate = () => {
    qc.invalidateQueries({ queryKey: ['settlement', 'detail', invoiceId] });
    onChanged();
  };

  const payM = useMutation({
    mutationFn: () =>
      settlementApi.recordPayment(invoiceId, { amount: Number(amount), method, memo: memo || undefined }),
    onSuccess: () => {
      setAmount('');
      setMemo('');
      setFormError(null);
      invalidate();
    },
    onError: () => setFormError(t('settlement.payFail')),
  });

  const issueM = useMutation({
    mutationFn: () => settlementApi.issue(invoiceId),
    onSuccess: invalidate,
  });

  // F083 세금계산서
  const taxQ = useQuery({
    queryKey: ['settlement', 'tax', invoiceId],
    queryFn: () => settlementApi.getTaxInvoice(invoiceId),
    retry: false,
  });
  const issueTaxM = useMutation({
    mutationFn: () => settlementApi.issueTaxInvoice(invoiceId),
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ['settlement', 'tax', invoiceId] });
    },
  });

  // F085 환불·취소
  const [showCancel, setShowCancel] = useState(false);
  const [cancelReason, setCancelReason] = useState('');
  const d = detailQ.data;
  const refundQ = useQuery({
    queryKey: ['settlement', 'refund', invoiceId],
    queryFn: () => settlementApi.refundQuote(invoiceId),
    enabled: showCancel && !!d && d.status !== 'cancelled',
    retry: false,
  });
  const cancelM = useMutation({
    mutationFn: () => settlementApi.cancel(invoiceId, { reason: cancelReason || undefined }),
    onSuccess: () => {
      setShowCancel(false);
      setCancelReason('');
      invalidate();
    },
  });

  const submitPayment = () => {
    const n = Number(amount);
    if (!Number.isFinite(n) || n <= 0) {
      setFormError(t('settlement.errPositive'));
      return;
    }
    if (d && n > d.outstanding) {
      setFormError(t('settlement.errExceed'));
      return;
    }
    setFormError(null);
    payM.mutate();
  };

  return (
    <div className="kx-settle__overlay" role="dialog" aria-modal="true" aria-label={t('settlement.modalAria')} onClick={onClose}>
      <div className="kx-settle__modal" onClick={(e) => e.stopPropagation()}>
        <div className="kx-settle__modal-head">
          <h2>{d ? d.invoiceNo : t('settlement.invoice')}</h2>
          <button className="kx-settle__close" aria-label={t('settlement.close')} onClick={onClose}>
            ✕
          </button>
        </div>

        {detailQ.isLoading ? (
          <div style={{ display: 'grid', gap: 8, padding: 16 }} aria-hidden="true">
            <Skeleton height={24} radius={6} />
            <Skeleton height={120} radius={8} />
            <Skeleton height={80} radius={8} />
          </div>
        ) : detailQ.isError || !d ? (
          <ErrorState message={t('settlement.detailError')} onRetry={() => detailQ.refetch()} />
        ) : (
          <div className="kx-settle__modal-body">
            <div className="kx-settle__meta">
              <div>
                <span className="kx-settle__meta-k">{t('settlement.colExhibitor')}</span>
                <span className="kx-settle__meta-v">{d.exhibitorName}</span>
              </div>
              <div>
                <span className="kx-settle__meta-k">{t('settlement.colCategory')}</span>
                <CategoryTag category={d.category} />
              </div>
              <div>
                <span className="kx-settle__meta-k">{t('settlement.colStatus')}</span>
                <StatusPill status={d.status} />
              </div>
              <div>
                <span className="kx-settle__meta-k">{t('settlement.colDue')}</span>
                <span className="kx-settle__meta-v">{d.dueDate ?? '-'}</span>
              </div>
            </div>

            {/* 라인아이템 */}
            <table className="kx-table kx-settle__lines">
              <thead>
                <tr>
                  <th>{t('settlement.liItem')}</th>
                  <th className="kx-num">{t('settlement.liQty')}</th>
                  <th className="kx-num">{t('settlement.liUnit')}</th>
                  <th className="kx-num">{t('settlement.liAmount')}</th>
                </tr>
              </thead>
              <tbody>
                {d.lineItems.length === 0 ? (
                  <tr>
                    <td colSpan={4} className="kx-settle__muted">
                      {t('settlement.noLines')}
                    </td>
                  </tr>
                ) : (
                  d.lineItems.map((li, i) => (
                    <tr key={`${li.category}-${i}`}>
                      <td>
                        <span className="kx-settle__cat">{li.category}</span> {li.description}
                      </td>
                      <td className="kx-num tnum">{li.quantity.toLocaleString()}</td>
                      <td className="kx-num tnum">{li.unitPrice.toLocaleString()}</td>
                      <td className="kx-num tnum">{li.amount.toLocaleString()}</td>
                    </tr>
                  ))
                )}
              </tbody>
              <tfoot>
                <tr>
                  <td colSpan={3}>{t('settlement.supplyAmount')}</td>
                  <td className="kx-num tnum">{d.subtotal.toLocaleString()}</td>
                </tr>
                <tr>
                  <td colSpan={3}>{t('settlement.vat')}</td>
                  <td className="kx-num tnum">{d.vat.toLocaleString()}</td>
                </tr>
                <tr className="kx-settle__total-row">
                  <td colSpan={3}>{t('settlement.grandTotal')}</td>
                  <td className="kx-num tnum">{d.total.toLocaleString()}</td>
                </tr>
                <tr>
                  <td colSpan={3}>{t('settlement.paidOutstanding')}</td>
                  <td className="kx-num tnum">
                    {d.paidAmount.toLocaleString()} / {d.outstanding.toLocaleString()}
                  </td>
                </tr>
              </tfoot>
            </table>

            {/* 수납 이력 */}
            <div className="kx-settle__pay-hist">
              <h3>{t('settlement.payHistory')}</h3>
              {d.payments.length === 0 ? (
                <p className="kx-settle__muted">{t('settlement.noPayments')}</p>
              ) : (
                <ul>
                  {d.payments.map((p) => (
                    <li key={p.id}>
                      <span className="tnum">{t('settlement.won', { v: p.amount.toLocaleString() })}</span>
                      <span className="kx-settle__pay-method">{p.method}</span>
                      {p.memo && <span className="kx-settle__pay-memo">{p.memo}</span>}
                      <span className="kx-settle__pay-date">{formatDate(p.recordedAt)}</span>
                    </li>
                  ))}
                </ul>
              )}
            </div>

            {/* 세금계산서(F083) */}
            <div className="kx-settle__tax">
              <h3>{t('settlement.taxTitle')}</h3>
              {taxQ.isLoading ? (
                <Skeleton height={60} radius={8} />
              ) : taxQ.data ? (
                <div className="kx-settle__tax-doc">
                  <div className="kx-settle__tax-row">
                    <span className="kx-settle__meta-k">{t('settlement.taxNo')}</span>
                    <span className="kx-settle__meta-v tnum">{taxQ.data.taxInvoiceNo}</span>
                  </div>
                  <div className="kx-settle__tax-row">
                    <span className="kx-settle__meta-k">{t('settlement.taxSupplier')}</span>
                    <span className="kx-settle__meta-v">{taxQ.data.supplierName}</span>
                  </div>
                  <div className="kx-settle__tax-row">
                    <span className="kx-settle__meta-k">{t('settlement.taxBuyer')}</span>
                    <span className="kx-settle__meta-v">{taxQ.data.buyerName}</span>
                  </div>
                  <div className="kx-settle__tax-row">
                    <span className="kx-settle__meta-k">{t('settlement.taxItem')}</span>
                    <span className="kx-settle__meta-v">{taxQ.data.itemSummary}</span>
                  </div>
                  <div className="kx-settle__tax-amounts">
                    <span>
                      {t('settlement.supplyAmount')}: <strong className="tnum">{taxQ.data.supplyAmount.toLocaleString()}</strong>
                    </span>
                    <span>
                      {t('settlement.vat')}: <strong className="tnum">{taxQ.data.vat.toLocaleString()}</strong>
                    </span>
                    <span>
                      {t('settlement.grandTotal')}: <strong className="tnum">{taxQ.data.total.toLocaleString()}</strong>
                    </span>
                  </div>
                  <p className="kx-settle__muted">{taxQ.data.issueNote}</p>
                </div>
              ) : (
                <p className="kx-settle__muted">{t('settlement.taxNone')}</p>
              )}
              {d.canManage && !taxQ.data && d.status !== 'pending' && d.status !== 'cancelled' && (
                <Button variant="secondary" onClick={() => issueTaxM.mutate()} disabled={issueTaxM.isPending}>
                  {issueTaxM.isPending ? t('settlement.taxIssuing') : t('settlement.taxIssue')}
                </Button>
              )}
              {issueTaxM.isError && (
                <p className="kx-settle__form-error" role="alert">{t('settlement.taxIssueFail')}</p>
              )}
            </div>

            {/* 매니저 액션 */}
            {d.canManage ? (
              <div className="kx-settle__actions">
                {d.status === 'cancelled' && (
                  <p className="kx-settle__muted">{t('settlement.cancelledNote')}</p>
                )}
                {d.status === 'pending' && (
                  <Button variant="secondary" onClick={() => issueM.mutate()} disabled={issueM.isPending}>
                    {issueM.isPending ? t('settlement.issuing') : t('settlement.issue')}
                  </Button>
                )}
                {d.status !== 'cancelled' && d.outstanding > 0 && (
                  <div className="kx-settle__pay-form">
                    <div className="kx-settle__pay-inputs">
                      <input
                        className="kx-input"
                        type="number"
                        min={1}
                        placeholder={t('settlement.payAmountPh')}
                        value={amount}
                        onChange={(e) => setAmount(e.target.value)}
                        aria-label={t('settlement.payAmount')}
                      />
                      <select
                        className="kx-select"
                        value={method}
                        onChange={(e) => setMethod(e.target.value as 'manual' | 'transfer' | 'card')}
                        aria-label={t('settlement.payMethod')}
                      >
                        <option value="transfer">{t('settlement.methodTransfer')}</option>
                        <option value="card">{t('settlement.methodCard')}</option>
                        <option value="manual">{t('settlement.methodOther')}</option>
                      </select>
                      <input
                        className="kx-input"
                        type="text"
                        placeholder={t('settlement.memoPh')}
                        value={memo}
                        onChange={(e) => setMemo(e.target.value)}
                        aria-label={t('settlement.memo')}
                      />
                      <Button variant="primary" onClick={submitPayment} disabled={payM.isPending}>
                        {payM.isPending ? t('settlement.recording') : t('settlement.recordPay')}
                      </Button>
                    </div>
                    {formError && <p className="kx-settle__form-error" role="alert">{formError}</p>}
                    <p className="kx-settle__muted">
                      {t('settlement.pgNote')}
                    </p>
                  </div>
                )}

                {/* 취소·환불(F085) */}
                {d.status !== 'cancelled' && (
                  <div className="kx-settle__cancel">
                    {!showCancel ? (
                      <Button variant="secondary" onClick={() => setShowCancel(true)}>
                        {t('settlement.cancelInvoice')}
                      </Button>
                    ) : (
                      <div className="kx-settle__cancel-box">
                        <h4>{t('settlement.refundPreview')}</h4>
                        {refundQ.isLoading ? (
                          <Skeleton height={80} radius={8} />
                        ) : refundQ.isError || !refundQ.data ? (
                          <ErrorState message={t('settlement.refundError')} onRetry={() => refundQ.refetch()} />
                        ) : (
                          <div className="kx-settle__refund">
                            <div className="kx-settle__refund-row">
                              <span>{t('settlement.refundBracket')}</span>
                              <strong>
                                {refundQ.data.bracketLabel}
                                {refundQ.data.daysBeforeEvent != null &&
                                  ` (D-${refundQ.data.daysBeforeEvent})`}
                              </strong>
                            </div>
                            <div className="kx-settle__refund-row">
                              <span>{t('settlement.refundRate')}</span>
                              <strong className="tnum">{refundQ.data.refundRatePercent}%</strong>
                            </div>
                            <div className="kx-settle__refund-row">
                              <span>{t('settlement.refundBase')}</span>
                              <strong className="tnum">{refundQ.data.baseAmount.toLocaleString()}</strong>
                            </div>
                            <div className="kx-settle__refund-row kx-settle__refund-row--em">
                              <span>{t('settlement.refundAmount')}</span>
                              <strong className="tnum">{refundQ.data.refundAmount.toLocaleString()}</strong>
                            </div>
                            <div className="kx-settle__refund-row">
                              <span>{t('settlement.forfeitAmount')}</span>
                              <strong className="tnum">{refundQ.data.forfeitAmount.toLocaleString()}</strong>
                            </div>
                            {!refundQ.data.dateResolved && (
                              <p className="kx-settle__form-error">{t('settlement.refundManual')}</p>
                            )}
                            <p className="kx-settle__muted">{refundQ.data.pgNote}</p>
                          </div>
                        )}
                        <input
                          className="kx-input"
                          type="text"
                          placeholder={t('settlement.cancelReasonPh')}
                          value={cancelReason}
                          onChange={(e) => setCancelReason(e.target.value)}
                          aria-label={t('settlement.cancelReason')}
                        />
                        <div className="kx-settle__cancel-actions">
                          <Button
                            variant="secondary"
                            onClick={() => {
                              setShowCancel(false);
                              setCancelReason('');
                            }}
                          >
                            {t('settlement.cancelAbort')}
                          </Button>
                          <Button
                            variant="primary"
                            onClick={() => cancelM.mutate()}
                            disabled={cancelM.isPending || refundQ.isLoading}
                          >
                            {cancelM.isPending ? t('settlement.cancelling') : t('settlement.cancelConfirm')}
                          </Button>
                        </div>
                        {cancelM.isError && (
                          <p className="kx-settle__form-error" role="alert">{t('settlement.cancelFail')}</p>
                        )}
                      </div>
                    )}
                  </div>
                )}
              </div>
            ) : (
              <p className="kx-settle__muted">{t('settlement.managerOnly')}</p>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

const TOOLTIP_STYLE = {
  fontSize: 12,
  borderRadius: 8,
  border: '1px solid #E4E7EC',
  boxShadow: '0 4px 12px rgba(16,24,40,0.1)',
} as const;

/** 원 금액 → 억/만 단위 축약(표시 전용, 서버 값 재계산 아님). */
function formatWon(v: number): string {
  if (v >= 1e8) return `₩${(v / 1e8).toFixed(2)}억`;
  if (v >= 1e4) return `₩${Math.round(v / 1e4).toLocaleString()}만`;
  return `₩${v.toLocaleString()}`;
}

function formatDate(iso: string | null): string {
  if (!iso) return '-';
  return iso.slice(0, 10);
}
