// ────────────────────────────────────────────────────────────────────
// AW-020 · Settlement Statement — issue modal
// ────────────────────────────────────────────────────────────────────

const STMT_DATA = {
  partner: 'Osaka Stay Collection',
  partnerId: 'PRT-2024-0048',
  contact: 'finance@osakastay.example',
  cat: 'Accommodation',
  type: 'B2C',
  period: '2026-03-01 ~ 2026-03-31',
  issuedAt: '2026-04-22 14:08:11 KST',
  stmtNo: 'STMT-B2C-2026-03-0048',
  settleId: 'STL-2026-03-0048',
  fuRows: [
    { date: '2026-03-04 11:22', id: 'VCH-2026-0481011', svc: 'Standard Twin · 2박 × 2', orig: 2400, pct: 100, net: 2400 },
    { date: '2026-03-09 09:48', id: 'VCH-2026-0481088', svc: 'Deluxe King · 1박',        orig: 1200, pct: 100, net: 1200 },
    { date: '2026-03-14 16:03', id: 'VCH-2026-0481145', svc: 'Family Suite · 3박',       orig: 3600, pct: 100, net: 3600 },
    { date: '2026-03-22 10:11', id: 'VCH-2026-0481209', svc: 'Standard Twin · 1박',      orig: 1200, pct: 100, net: 1200 },
    { date: '2026-03-28 14:55', id: 'VCH-2026-0481288', svc: 'Deluxe King · 2박',        orig: 2400, pct: 100, net: 2400 },
  ],
  fuMore: 91, fuTotal: 122400,

  exRows: [
    { date: '2026-03-31 24:00', id: 'VCH-2026-0480200', svc: 'Standard Twin · 1박',  orig: 800, pct: 30, net: 240 },
    { date: '2026-03-31 24:00', id: 'VCH-2026-0480211', svc: 'Standard Twin · 1박',  orig: 800, pct: 30, net: 240 },
    { date: '2026-03-31 24:00', id: 'VCH-2026-0480245', svc: 'Deluxe King · 1박',    orig: 800, pct: 30, net: 240 },
  ],
  exMore: 19, exTotal: 5280,

  rvRows: [
    { date: '2026-04-18 11:24', id: 'IVH-2026-A0480112', svc: 'Standard Twin · 1박', orig: 640, pct: 100, net: -640, srcStl: 'STL-2026-02-0048', reason: 'CANCELLED — 소비자 이의 제기 (시설 청결 불만)', memo: 'CS팀 #cs-9281 검토 중', dday: null, status: 'DISPUTED' },
    { date: '2026-04-08 09:11', id: 'IVH-2026-A0480245', svc: 'Family Suite · 1박',  orig: 320, pct: 100, net: -320, srcStl: 'STL-2026-02-0048', reason: 'CANCELLED — 체크인 무산',                  memo: '예약일 변경 협의 중',  dday: 6,    status: 'GRACE_PERIOD' },
    { date: '2026-04-12 15:32', id: 'IVH-2026-A0480501', svc: 'Standard Twin · 1박', orig: 320, pct: 100, net: -320, srcStl: 'STL-2026-02-0048', reason: 'CANCELLED — 시설 이용 불가',              memo: '파트너 응대 진행',     dday: 2,    status: 'GRACE_PERIOD' },
    { date: '2026-04-19 10:20', id: 'IVH-2026-A0480398', svc: 'Standard Twin · 1박', orig: 320, pct: 100, net: -320, srcStl: 'STL-2026-02-0048', reason: 'CANCELLED — 소비자 철회',                memo: '환불 철회 처리 (정상)', dday: null, status: 'WITHDRAWN' },
  ],

  // computed
  exDeductable: 5280, // shown net (30%)
  exFull: 17600,      // 100% face value
  rvTotal: -1600,
  fee: 0,
};

// helpers
const fmtMon = v => `USD ${Number(v).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
const fmtSign = v => (v < 0 ? `−USD ${Math.abs(v).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : `USD ${Number(v).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`);

// ── KARE logo ───────────────────────────────────────────────────
const KareLogo = ({ size = 28, dark = false }) => (
  <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
    <div style={{
      width: size, height: size, borderRadius: 6,
      background: dark ? '#0D7A6E' : '#0D7A6E',
      display: 'grid', placeItems: 'center',
      fontFamily: 'Inter', fontWeight: 700, fontSize: size * 0.5,
      color: '#fff', letterSpacing: '-0.04em',
    }}>K</div>
    <div style={{ fontFamily: 'Inter', fontSize: size * 0.55, fontWeight: 700, color: '#0D7A6E', letterSpacing: '-0.02em' }}>KARE</div>
  </div>
);

// ── Segmented control for output mode ───────────────────────────
const ModeSegment = ({ value, onChange }) => {
  const opts = [
    { id: 'screen', label: '화면 보기', icon: <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="14" rx="2"/><line x1="8" y1="20" x2="16" y2="20"/><line x1="12" y1="18" x2="12" y2="20"/></svg> },
    { id: 'print',  label: '인쇄',     icon: <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 01-2-2v-5a2 2 0 012-2h16a2 2 0 012 2v5a2 2 0 01-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></svg> },
    { id: 'pdf',    label: 'PDF',      icon: <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/></svg> },
    { id: 'csv',    label: 'CSV',      icon: <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/></svg> },
  ];
  return (
    <div style={{
      display: 'inline-flex', padding: 3,
      background: 'var(--n-100)', border: '1px solid var(--n-200)', borderRadius: 7,
    }}>
      {opts.map(o => {
        const active = value === o.id;
        return (
          <button key={o.id} onClick={() => onChange(o.id)} style={{
            display: 'inline-flex', alignItems: 'center', gap: 5,
            padding: '5px 11px', borderRadius: 5, border: 'none',
            background: active ? '#fff' : 'transparent',
            boxShadow: active ? '0 1px 2px rgba(0,0,0,0.05), 0 0 0 1px var(--n-200)' : 'none',
            fontFamily: 'Inter', fontSize: 11.5, fontWeight: 600,
            color: active ? 'var(--n-900)' : 'var(--n-500)',
            cursor: 'pointer',
          }}>{o.icon}{o.label}</button>
        );
      })}
    </div>
  );
};

// ── Section A · Statement header ───────────────────────────────
const StmtHeader = ({ d, mode }) => (
  <div style={{
    padding: '24px 32px', borderBottom: '2px solid #0D7A6E',
    display: 'flex', alignItems: 'flex-start', gap: 20,
  }}>
    <div style={{ flex: 1 }}>
      <KareLogo size={28}/>
      <div style={{
        marginTop: 12,
        fontFamily: 'Inter', fontSize: 22, fontWeight: 700,
        color: 'var(--n-900)', letterSpacing: '-0.02em',
      }}>Settlement Statement</div>
      <div style={{ marginTop: 2, fontSize: 11.5, color: 'var(--n-500)' }}>
        {d.type === 'B2C' ? 'Partner Settlement (B2C)' : 'Corporate Settlement (B2B)'} · {d.cat}
      </div>
    </div>
    <table style={{ borderCollapse: 'collapse', fontSize: 11.5 }}>
      <tbody>
        <tr><td style={metaTd}>거래처</td><td style={metaTdV}>{d.partner}</td></tr>
        <tr><td style={metaTd}>파트너 ID</td><td style={metaTdVMono}>{d.partnerId}</td></tr>
        <tr><td style={metaTd}>정산 기간</td><td style={metaTdVMono}>{d.period}</td></tr>
        <tr><td style={metaTd}>발행 일시</td><td style={metaTdVMono}>{d.issuedAt}</td></tr>
        <tr><td style={metaTd}>명세서 번호</td><td style={metaTdVMono}>{d.stmtNo}</td></tr>
        <tr><td style={metaTd}>정산 ID</td><td style={metaTdVMono}>
          <span style={{ color: mode === 'print' ? 'var(--n-700)' : 'var(--primary)' }}>{d.settleId}</span>
        </td></tr>
      </tbody>
    </table>
  </div>
);

const metaTd     = { padding: '2px 12px 2px 0', color: 'var(--n-500)', fontFamily: 'Inter', textAlign: 'left', fontWeight: 500, whiteSpace: 'nowrap', verticalAlign: 'top' };
const metaTdV    = { padding: '2px 0', color: 'var(--n-900)', fontFamily: 'Inter', fontWeight: 600 };
const metaTdVMono = { padding: '2px 0', color: 'var(--n-900)', fontFamily: 'JetBrains Mono, monospace', fontWeight: 600, fontSize: 11 };

// ── Section B · Summary box ────────────────────────────────────
const StmtSummary = ({ d, finalAmount }) => (
  <div style={{ padding: '20px 32px', borderBottom: '1px solid var(--n-200)' }}>
    <div style={{ fontFamily: 'Inter', fontSize: 11, fontWeight: 700, color: 'var(--n-500)', letterSpacing: '0.08em', marginBottom: 12 }}>
      A. 정산 요약 (SUMMARY)
    </div>
    <div style={{
      display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)',
      border: '1px solid var(--n-300)', borderRadius: 6, overflow: 'hidden',
    }}>
      <SummaryCell label="FULLY_USED" sub="100% 정산" amount={d.fuTotal} count={d.fuRows.length + d.fuMore}/>
      <SummaryCell label="EXPIRED" sub="환수 30%" amount={d.exDeductable} note={`face USD ${d.exFull.toLocaleString()} × 30%`} count={d.exRows.length + d.exMore}/>
      <SummaryCell label="REVERSAL" sub="확정 차감" amount={d.rvTotal} negative count={d.rvRows.length}/>
      <SummaryCell label="수수료" sub="MVP · 0%" amount={-d.fee} count={null}/>
      <SummaryCell label="최종 지급액" amount={finalAmount} primary big/>
    </div>
  </div>
);

const SummaryCell = ({ label, sub, amount, count, negative, primary, big, note }) => (
  <div style={{
    padding: big ? '14px 16px' : '12px 14px',
    background: primary ? '#F0FAF8' : '#fff',
    borderRight: '1px solid var(--n-200)',
    display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
    minHeight: 86,
  }}>
    <div>
      <div style={{
        fontFamily: 'JetBrains Mono, monospace', fontSize: 10, fontWeight: 700,
        color: primary ? 'var(--primary)' : 'var(--n-500)', letterSpacing: '0.06em',
      }}>{label}</div>
      {sub && <div style={{ fontSize: 10, color: 'var(--n-500)', marginTop: 2 }}>{sub}</div>}
    </div>
    <div>
      <div style={{
        fontFamily: 'JetBrains Mono, monospace',
        fontSize: big ? 19 : 14, fontWeight: 700,
        color: primary ? 'var(--primary)' : negative || amount < 0 ? '#DC2626' : 'var(--n-900)',
        fontVariantNumeric: 'tabular-nums',
        letterSpacing: '-0.01em',
      }}>{fmtSign(amount)}</div>
      {count != null && (
        <div style={{ fontSize: 10, color: 'var(--n-500)', marginTop: 2, fontFamily: 'JetBrains Mono, monospace' }}>
          {count}건{note ? ` · ${note}` : ''}
        </div>
      )}
      {note && count == null && (
        <div style={{ fontSize: 9.5, color: 'var(--n-500)', marginTop: 2 }}>{note}</div>
      )}
    </div>
  </div>
);

// ── Section C · Voucher detail table ───────────────────────────
const StmtTable = ({ d, mode }) => (
  <div style={{ padding: '20px 32px', borderBottom: '1px solid var(--n-200)' }}>
    <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
      <div style={{ fontFamily: 'Inter', fontSize: 11, fontWeight: 700, color: 'var(--n-500)', letterSpacing: '0.08em' }}>
        B. VOUCHER 명세 (LINE ITEMS)
      </div>
      <div style={{ fontSize: 10.5, color: 'var(--n-500)', fontFamily: 'JetBrains Mono, monospace' }}>
        통화: USD · 정렬: 처리 일시 ↑
      </div>
    </div>

    <table style={stmtTable}>
      <thead>
        <tr style={{ borderBottom: '1.5px solid var(--n-700)' }}>
          <th style={{ ...stmtTh, width: 130 }}>처리 일시</th>
          <th style={{ ...stmtTh, width: 165 }}>Voucher ID</th>
          <th style={stmtTh}>Item · 서비스</th>
          <th style={{ ...stmtTh, ...stmtThR, width: 90 }}>원금 (Face)</th>
          <th style={{ ...stmtTh, ...stmtThR, width: 70 }}>조정율</th>
          <th style={{ ...stmtTh, ...stmtThR, width: 110 }}>정산액 (Net)</th>
        </tr>
      </thead>
      <tbody>
        {/* FULLY_USED group */}
        <GroupHeader label="FULLY_USED" count={d.fuRows.length + d.fuMore} subtotal={d.fuTotal} dot="#6B7280"/>
        {d.fuRows.map((r, i) => <StmtRow key={r.id} r={r} idx={i + 1} mode={mode}/>)}
        {d.fuMore > 0 && <MoreRow count={d.fuMore} amount={d.fuTotal - d.fuRows.reduce((s, r) => s + r.net, 0)}/>}

        {/* EXPIRED group */}
        <GroupHeader label="EXPIRED · 30% 환수" count={d.exRows.length + d.exMore} subtotal={d.exDeductable} dot="#D97706"/>
        {d.exRows.map((r, i) => <StmtRow key={r.id} r={r} idx={i + 1} mode={mode}/>)}
        {d.exMore > 0 && <MoreRow count={d.exMore} amount={d.exDeductable - d.exRows.reduce((s, r) => s + r.net, 0)}/>}

        {/* REVERSAL group */}
        {d.rvRows.length > 0 && (
          <>
            <GroupHeader label="REVERSAL · 차감" count={d.rvRows.length} subtotal={d.rvTotal} dot="#DC2626" reversal/>
            {d.rvRows.map((r, i) => <StmtRowReversal key={r.id} r={r} idx={i + 1} mode={mode}/>)}
          </>
        )}

        {/* Grand total */}
        <tr style={{ borderTop: '2px solid var(--n-900)' }}>
          <td colSpan={5} style={{ padding: '12px 8px', textAlign: 'right', fontFamily: 'Inter', fontSize: 12, fontWeight: 700, color: 'var(--n-900)' }}>
            합계 (Grand Total)
          </td>
          <td style={{ padding: '12px 8px', textAlign: 'right', fontFamily: 'JetBrains Mono, monospace', fontSize: 14, fontWeight: 700, color: 'var(--primary)' }}>
            {fmtSign(d.fuTotal + d.exDeductable + d.rvTotal)}
          </td>
        </tr>
      </tbody>
    </table>
  </div>
);

const GroupHeader = ({ label, count, subtotal, dot, reversal }) => (
  <tr style={{ background: reversal ? 'var(--error-bg)' : 'var(--n-050)' }}>
    <td colSpan={3} style={{ padding: '8px 8px', fontFamily: 'JetBrains Mono, monospace', fontSize: 11, fontWeight: 700, color: reversal ? '#991B1B' : 'var(--n-700)', borderBottom: '1px solid var(--n-300)', borderTop: '1px solid var(--n-300)' }}>
      <span style={{ display: 'inline-block', width: 6, height: 6, borderRadius: '50%', background: dot, marginRight: 8, verticalAlign: 'middle' }}/>
      {label}
      <span style={{ marginLeft: 10, color: 'var(--n-500)', fontWeight: 500 }}>{count}건</span>
    </td>
    <td colSpan={3} style={{ padding: '8px 8px', textAlign: 'right', fontFamily: 'JetBrains Mono, monospace', fontSize: 11.5, fontWeight: 700, color: reversal ? '#DC2626' : 'var(--n-900)', borderBottom: '1px solid var(--n-300)', borderTop: '1px solid var(--n-300)' }}>
      소계 {fmtSign(subtotal)}
    </td>
  </tr>
);

const StmtRow = ({ r, idx, mode }) => (
  <tr style={{ borderBottom: '1px solid var(--n-100)' }}>
    <td style={stmtTd}>
      <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10.5, color: 'var(--n-700)' }}>{r.date}</span>
    </td>
    <td style={stmtTd}>
      <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: mode === 'print' ? 'var(--n-900)' : 'var(--primary)', fontWeight: 600 }}>{r.id}</span>
    </td>
    <td style={stmtTd}>{r.svc}</td>
    <td style={stmtTdR}>{fmtMon(r.orig)}</td>
    <td style={stmtTdR}>
      <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10.5, color: r.pct === 100 ? 'var(--n-500)' : '#92400E' }}>{r.pct}%</span>
    </td>
    <td style={{ ...stmtTdR, fontWeight: 600 }}>{fmtMon(r.net)}</td>
  </tr>
);

const StmtRowReversal = ({ r, idx, mode }) => (
  <>
    <tr style={{ background: 'var(--error-bg)', borderBottom: '1px dashed #FCA5A5' }}>
      <td style={stmtTd}>
        <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10.5, color: 'var(--n-700)' }}>{r.date}</span>
      </td>
      <td style={stmtTd}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
          <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="#DC2626" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
            <polyline points="9 14 4 9 9 4"/><path d="M20 20v-7a4 4 0 00-4-4H4"/>
          </svg>
          <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--n-900)', fontWeight: 600 }}>{r.id}</span>
        </span>
      </td>
      <td style={{ ...stmtTd, color: 'var(--n-700)' }}>
        {mode === 'print' && <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, fontWeight: 700, color: '#991B1B', marginRight: 6 }}>(REVERSAL)</span>}
        {r.svc}
      </td>
      <td style={stmtTdR}>{fmtMon(r.orig)}</td>
      <td style={stmtTdR}>
        <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10.5, color: 'var(--n-500)' }}>—</span>
      </td>
      <td style={{ ...stmtTdR, color: '#DC2626', fontWeight: 700 }}>{fmtSign(r.net)}</td>
    </tr>
    <tr style={{ background: 'rgba(254,242,242,0.4)', borderBottom: '1px solid var(--n-100)' }}>
      <td colSpan={6} style={{ padding: '4px 8px 8px 8px', fontSize: 10.5, color: 'var(--n-700)' }}>
        <span style={{ fontFamily: 'JetBrains Mono, monospace', color: 'var(--n-500)', marginRight: 8 }}>↳</span>
        <span style={{ fontWeight: 600 }}>원본 정산:</span> <span style={{ fontFamily: 'JetBrains Mono, monospace', color: mode === 'print' ? 'var(--n-700)' : 'var(--primary)' }}>{r.srcStl}</span>
        <span style={{ color: 'var(--n-300)', margin: '0 8px' }}>·</span>
        <span style={{ fontWeight: 600 }}>사유:</span> {r.reason}
        {r.dday != null && (
          <>
            <span style={{ color: 'var(--n-300)', margin: '0 8px' }}>·</span>
            <span style={{ fontFamily: 'JetBrains Mono, monospace', color: '#92400E', fontWeight: 600 }}>유예 D-{r.dday}</span>
          </>
        )}
        <span style={{ color: 'var(--n-300)', margin: '0 8px' }}>·</span>
        <span style={{ fontWeight: 600 }}>관리자 메모:</span> <span style={{ color: 'var(--n-500)' }}>{r.memo}</span>
      </td>
    </tr>
  </>
);

const MoreRow = ({ count, amount }) => (
  <tr style={{ borderBottom: '1px solid var(--n-100)' }}>
    <td colSpan={3} style={{ padding: '7px 8px', fontSize: 11, color: 'var(--n-500)', fontStyle: 'italic' }}>
      외 {count}건 (생략) · 전체는 PDF/CSV에서 확인
    </td>
    <td colSpan={2}/>
    <td style={{ ...stmtTdR, color: 'var(--n-500)', fontStyle: 'italic' }}>{fmtMon(amount)}</td>
  </tr>
);

const stmtTable = { width: '100%', borderCollapse: 'collapse', fontFamily: 'Inter', fontSize: 11.5 };
const stmtTh    = { textAlign: 'left',  padding: '8px 8px', fontFamily: 'Inter', fontSize: 10.5, fontWeight: 700, color: 'var(--n-700)', letterSpacing: '0.04em' };
const stmtThR   = { textAlign: 'right' };
const stmtTd    = { padding: '8px 8px', color: 'var(--n-700)', verticalAlign: 'middle' };
const stmtTdR   = { padding: '8px 8px', color: 'var(--n-900)', textAlign: 'right', fontFamily: 'JetBrains Mono, monospace', fontVariantNumeric: 'tabular-nums' };

// ── Section D · REVERSAL roll-forward ──────────────────────────
const ReversalRoll = ({ d, finalAmount }) => {
  const positive = d.fuTotal + d.exDeductable;
  return (
    <div style={{ padding: '20px 32px', borderBottom: '1px solid var(--n-200)' }}>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
        <div style={{ fontFamily: 'Inter', fontSize: 11, fontWeight: 700, color: 'var(--n-500)', letterSpacing: '0.08em' }}>
          C. REVERSAL 역산 내역 (ROLL-FORWARD)
        </div>
        <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10.5, color: '#991B1B', fontWeight: 700, padding: '2px 8px', background: 'var(--error-bg)', border: '1px solid #FECACA', borderRadius: 4 }}>
          {d.rvRows.length}건 · {fmtSign(d.rvTotal)}
        </span>
      </div>

      {/* Equation */}
      <div style={{
        padding: '14px 16px',
        background: '#F9FAFB', border: '1px solid var(--n-200)', borderRadius: 6,
        display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap',
        fontFamily: 'JetBrains Mono, monospace', fontSize: 12,
      }}>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
          <span style={{ fontSize: 9.5, color: 'var(--n-500)', fontWeight: 600 }}>정산 대상 (FU + EX)</span>
          <span style={{ fontSize: 14, color: 'var(--n-900)', fontWeight: 700 }}>{fmtMon(positive)}</span>
        </div>
        <span style={{ fontSize: 18, color: 'var(--n-400)', fontWeight: 300 }}>−</span>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
          <span style={{ fontSize: 9.5, color: 'var(--n-500)', fontWeight: 600 }}>REVERSAL 확정 차감</span>
          <span style={{ fontSize: 14, color: '#DC2626', fontWeight: 700 }}>{fmtMon(Math.abs(d.rvTotal))}</span>
        </div>
        <span style={{ fontSize: 18, color: 'var(--n-400)', fontWeight: 300 }}>=</span>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
          <span style={{ fontSize: 9.5, color: 'var(--primary)', fontWeight: 700 }}>최종 지급액</span>
          <span style={{ fontSize: 17, color: 'var(--primary)', fontWeight: 700, letterSpacing: '-0.015em' }}>{fmtMon(finalAmount)}</span>
        </div>

        <div style={{ marginLeft: 'auto', display: 'flex', flexDirection: 'column', alignItems: 'flex-end', borderLeft: '1px solid var(--n-200)', paddingLeft: 16 }}>
          <span style={{ fontFamily: 'Inter', fontSize: 9.5, color: 'var(--n-500)', fontWeight: 600 }}>유예 중 잔여</span>
          <span style={{ fontSize: 12, color: '#92400E', fontWeight: 700 }}>2건 (다음 기로 이월)</span>
        </div>
      </div>

      {/* Per-item roll list */}
      <table style={{ ...stmtTable, marginTop: 12 }}>
        <thead>
          <tr style={{ borderBottom: '1px solid var(--n-300)' }}>
            <th style={{ ...stmtTh, width: 165 }}>역산 IVH ID</th>
            <th style={stmtTh}>원본 정산</th>
            <th style={stmtTh}>상태 / 유예</th>
            <th style={{ ...stmtTh, ...stmtThR, width: 110 }}>차감액</th>
          </tr>
        </thead>
        <tbody>
          {d.rvRows.map((r, i) => (
            <tr key={r.id} style={{ borderBottom: i < d.rvRows.length - 1 ? '1px solid var(--n-100)' : 'none' }}>
              <td style={stmtTd}>
                <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--n-900)', fontWeight: 600 }}>{r.id}</span>
              </td>
              <td style={stmtTd}>
                <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10.5, color: 'var(--primary)' }}>{r.srcStl}</span>
              </td>
              <td style={stmtTd}>
                <RvStatusInline status={r.status} dday={r.dday}/>
              </td>
              <td style={{ ...stmtTdR, color: '#DC2626', fontWeight: 700 }}>{fmtSign(r.net)}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

const RvStatusInline = ({ status, dday }) => {
  const map = {
    GRACE_PERIOD: { color: '#92400E', bg: '#FFFBEB', border: '#FDE68A', label: `유예 중 D-${dday}` },
    DISPUTED:     { color: '#6D28D9', bg: '#F5F3FF', border: '#DDD6FE', label: '이의 제기 (DSP)' },
    WITHDRAWN:    { color: '#6B7280', bg: '#F3F4F6', border: '#D1D5DB', label: '철회' },
    CONFIRMED:    { color: '#991B1B', bg: '#FEF2F2', border: '#FCA5A5', label: '확정' },
  };
  const s = map[status];
  return (
    <span style={{
      display: 'inline-block',
      padding: '2px 7px', borderRadius: 4,
      background: s.bg, border: `1px solid ${s.border}`,
      fontFamily: 'Inter', fontSize: 10.5, fontWeight: 700, color: s.color,
    }}>{s.label}</span>
  );
};

// ── Section E · Footer notes (always shown on doc) ─────────────
const StmtNotes = ({ d, mode }) => (
  <div style={{ padding: '20px 32px 24px 32px' }}>
    <div style={{ fontFamily: 'Inter', fontSize: 11, fontWeight: 700, color: 'var(--n-500)', letterSpacing: '0.08em', marginBottom: 10 }}>
      D. 안내 (NOTES)
    </div>
    <ul style={{ margin: 0, padding: '0 0 0 18px', fontSize: 11, color: 'var(--n-700)', lineHeight: 1.65 }}>
      <li>본 명세서는 KARE 정산 시스템 BD-007 MVP 기준이며 자동 송금되지 않습니다. 회계팀 수동 처리용 참조 자료입니다.</li>
      <li>EXPIRED 항목은 카테고리별 정책에 따라 30% 환수율이 적용되었습니다 (Accommodation).</li>
      <li>REVERSAL 차감은 GRACE_PERIOD 만료 후 CONFIRMED 상태로 전환된 건에 한해 다음 정산에서 자동 차감됩니다.</li>
      <li>이의 제기 (DISPUTED) 항목은 해결 시까지 차감 보류되며 재계산은 회계팀 지원 ID 기반 수동 정정으로 처리됩니다.</li>
      <li>본 PDF는 발행 시점({d.issuedAt})의 데이터를 기준으로 합니다. 이후 데이터 변경은 정정 명세서 발행이 필요합니다.</li>
    </ul>
    <div style={{ marginTop: 16, paddingTop: 12, borderTop: '1px solid var(--n-200)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
      <div style={{ fontSize: 10, color: 'var(--n-500)' }}>
        KARE Settlement System · BD-007 · v1.2 · 본 문서는 KARE Inc. 와 {d.partner} 간 정산 참조 자료입니다.
      </div>
      <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: 'var(--n-500)' }}>
        Page 1 / 1 · 발행자: 김운영 (admin@kare.example)
      </div>
    </div>
  </div>
);

// ── CSV preview ────────────────────────────────────────────────
const CsvPreview = ({ d }) => {
  const lines = [
    `# KARE Settlement Statement — ${d.partner}`,
    `# stmt_no=${d.stmtNo} | period=${d.period} | issued_at=${d.issuedAt}`,
    `# encoding=UTF-8 BOM | delimiter=, | quote="`,
    ``,
    `processed_at,voucher_id,group,service,face_amount_usd,adjust_pct,net_amount_usd,reversal_source,reason`,
    ...d.fuRows.slice(0, 3).map(r => `${r.date},${r.id},FULLY_USED,"${r.svc}",${r.orig.toFixed(2)},${r.pct},${r.net.toFixed(2)},,`),
    `# ... ${d.fuRows.length + d.fuMore - 3} more FULLY_USED rows`,
    ...d.exRows.slice(0, 2).map(r => `${r.date},${r.id},EXPIRED,"${r.svc}",${r.orig.toFixed(2)},${r.pct},${r.net.toFixed(2)},,`),
    `# ... ${d.exRows.length + d.exMore - 2} more EXPIRED rows`,
    ...d.rvRows.slice(0, 2).map(r => `${r.date},${r.id},REVERSAL,"${r.svc}",${r.orig.toFixed(2)},,-${Math.abs(r.net).toFixed(2)},${r.srcStl},"${r.reason}"`),
    `# ... ${d.rvRows.length - 2} more REVERSAL rows`,
    ``,
    `# SUMMARY`,
    `# fully_used_total,${d.fuTotal.toFixed(2)}`,
    `# expired_total,${d.exDeductable.toFixed(2)}`,
    `# reversal_total,${d.rvTotal.toFixed(2)}`,
    `# final_payout,${(d.fuTotal + d.exDeductable + d.rvTotal).toFixed(2)}`,
  ];
  return (
    <div style={{
      padding: '20px 32px',
      background: '#0F172A', color: '#E2E8F0',
      fontFamily: 'JetBrains Mono, monospace', fontSize: 11.5,
      lineHeight: 1.7, minHeight: 600,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12, paddingBottom: 10, borderBottom: '1px solid #334155' }}>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#10B981" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="9" y1="21" x2="9" y2="9"/>
        </svg>
        <span style={{ color: '#10B981', fontWeight: 700, fontSize: 11 }}>CSV PREVIEW</span>
        <span style={{ color: '#64748B', fontSize: 10, marginLeft: 'auto' }}>UTF-8 BOM · ,(comma) · 첫 처리 항목 일부 + 요약 메타 라인 포함</span>
      </div>
      <pre style={{ margin: 0, whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>{lines.map((l, i) => (
        <div key={i} style={{ display: 'flex' }}>
          <span style={{ color: '#475569', width: 30, flexShrink: 0, textAlign: 'right', paddingRight: 12, userSelect: 'none' }}>{i + 1}</span>
          <span style={{ color: l.startsWith('#') ? '#94A3B8' : l.startsWith('processed_at') ? '#22D3EE' : '#E2E8F0' }}>{l || ' '}</span>
        </div>
      ))}</pre>
    </div>
  );
};

// ── Main statement document ────────────────────────────────────
const StatementDoc = ({ d, mode, error }) => {
  const finalAmount = d.fuTotal + d.exDeductable + d.rvTotal;

  if (mode === 'csv') {
    return <CsvPreview d={d}/>;
  }

  return (
    <div style={{
      background: '#fff',
      ...(mode === 'print' ? { boxShadow: 'none' } : {}),
    }}>
      <StmtHeader d={d} mode={mode}/>
      <StmtSummary d={d} finalAmount={finalAmount}/>
      <StmtTable d={d} mode={mode}/>
      {d.rvRows.length > 0 && <ReversalRoll d={d} finalAmount={finalAmount}/>}
      <StmtNotes d={d} mode={mode}/>

      {mode === 'pdf' && (
        <div style={{
          position: 'absolute', bottom: 24, left: '50%', transform: 'translateX(-50%)',
          padding: '6px 14px', background: 'rgba(13,122,110,0.92)',
          borderRadius: 999, color: '#fff',
          fontFamily: 'Inter', fontSize: 10.5, fontWeight: 700, letterSpacing: '0.04em',
          display: 'inline-flex', alignItems: 'center', gap: 6,
        }}>
          <svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" stroke="currentColor" strokeWidth="0"/></svg>
          PDF PREVIEW · A4
        </div>
      )}
    </div>
  );
};

// ── Modal frame ────────────────────────────────────────────────
const StatementIssueModal = ({ variant = 'screen' }) => {
  const d = variant === 'no-rv'
    ? { ...STMT_DATA, rvRows: [], rvTotal: 0 }
    : STMT_DATA;
  const error = variant === 'error';
  const isPrint = variant === 'print';
  const isPdf   = variant === 'pdf';
  const isCsv   = variant === 'csv';
  const mode = isPrint ? 'print' : isPdf ? 'pdf' : isCsv ? 'csv' : 'screen';

  const [fmt, setFmt] = React.useState('PDF');

  // PRINT → no chrome
  if (isPrint) {
    return (
      <div style={{
        position: 'absolute', inset: 0,
        background: '#fff',
      }}>
        <div style={{
          maxWidth: 920, margin: '0 auto', padding: '0',
          background: '#fff',
          fontFamily: 'Pretendard, Inter, sans-serif',
        }}>
          <StatementDoc d={d} mode="print" error={false}/>
        </div>
        {/* Print marker */}
        <div style={{
          position: 'absolute', top: 12, right: 12,
          padding: '4px 10px', background: 'var(--n-100)',
          border: '1px dashed var(--n-300)', borderRadius: 4,
          fontFamily: 'JetBrains Mono, monospace', fontSize: 9.5, color: 'var(--n-500)', fontWeight: 700,
        }}>PRINT MODE · chrome 제거 · 흑백 우선</div>
      </div>
    );
  }

  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: 'rgba(17,24,39,0.55)',
      display: 'grid', placeItems: 'center',
      padding: '20px',
    }}>
      <div style={{
        width: '100%', maxWidth: 1040,
        background: '#fff', borderRadius: 10,
        boxShadow: '0 24px 48px -12px rgba(0,0,0,0.3)',
        display: 'flex', flexDirection: 'column', overflow: 'hidden',
        maxHeight: 'calc(100vh - 40px)',
      }}>
        {/* Header */}
        <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--n-200)', display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 11, color: 'var(--n-500)', fontWeight: 600, marginBottom: 1 }}>
              정산 집계 <span style={{ color: 'var(--n-300)', margin: '0 5px' }}>›</span> 명세서 발행
            </div>
            <div style={{ fontFamily: 'Inter', fontSize: 16, fontWeight: 700, color: 'var(--n-900)' }}>
              정산 명세서 — {d.period} · <span style={{ color: 'var(--n-500)', fontWeight: 500 }}>{d.partner}</span>
            </div>
          </div>
          <ModeSegment value={mode} onChange={() => {}}/>
          <button style={{ width: 32, height: 32, borderRadius: 6, background: 'transparent', border: '1px solid var(--n-200)', color: 'var(--n-500)', cursor: 'pointer', display: 'grid', placeItems: 'center' }}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
          </button>
        </div>

        {/* Body — paper background */}
        <div style={{
          flex: 1,
          background: isCsv ? '#0F172A' : '#E5E7EB',
          padding: isCsv ? 0 : '24px 28px',
        }}>
          {error ? (
            <ErrorState/>
          ) : (
            <div style={{
              maxWidth: isCsv ? '100%' : 920, margin: '0 auto',
              background: '#fff',
              boxShadow: isCsv ? 'none' : '0 1px 3px rgba(0,0,0,0.08), 0 8px 24px -8px rgba(0,0,0,0.12)',
              borderRadius: isCsv ? 0 : 4,
              position: 'relative',
            }}>
              <StatementDoc d={d} mode={mode} error={error}/>
            </div>
          )}
        </div>

        {/* Footer */}
        <div style={{ padding: '12px 20px', borderTop: '1px solid var(--n-200)', background: '#fff', display: 'flex', alignItems: 'center', gap: 12 }}>
          <div style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 8 }}>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="var(--n-500)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/>
            </svg>
            <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 11, color: 'var(--n-500)' }}>
              KARE_Settlement_{d.type}_{d.partnerId.replace('PRT-', '')}_2026-03.{fmt.toLowerCase()}
            </span>
            <span style={{ fontSize: 10.5, color: 'var(--n-400)', marginLeft: 4 }}>
              · 명세서 SHA: a8f3…2d11 · ~ 184 KB
            </span>
          </div>

          <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 10.5, color: 'var(--success)' }}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2l-3.5-3.5-1.4 1.4L9 19l11-11-1.4-1.4z"/></svg>
            <span style={{ fontFamily: 'Inter', fontWeight: 600 }}>SETTLED 상태 — 발행 가능</span>
          </div>

          <select value={fmt} onChange={e => setFmt(e.target.value)} style={{
            padding: '7px 10px', background: '#fff',
            border: '1px solid var(--n-300)', borderRadius: 6,
            fontFamily: 'Inter', fontSize: 12, fontWeight: 600, color: 'var(--n-700)',
            cursor: 'pointer', outline: 'none',
          }}>
            <option>PDF</option>
            <option>CSV</option>
            <option>PDF + CSV (zip)</option>
          </select>

          <button style={{ padding: '8px 14px', background: '#fff', border: '1px solid var(--n-300)', borderRadius: 6, color: 'var(--n-700)', fontFamily: 'Inter', fontSize: 12, fontWeight: 600, cursor: 'pointer' }}>
            닫기
          </button>
          <button disabled={error} style={{
            padding: '8px 16px',
            background: error ? 'var(--n-100)' : 'var(--primary)',
            border: 'none', borderRadius: 6,
            color: error ? 'var(--n-400)' : '#fff',
            fontFamily: 'Inter', fontSize: 12, fontWeight: 700,
            cursor: error ? 'not-allowed' : 'pointer',
            display: 'inline-flex', alignItems: 'center', gap: 6,
          }}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
              <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>
            </svg>
            다운로드
          </button>
        </div>
      </div>
    </div>
  );
};

// ── Error state ────────────────────────────────────────────────
const ErrorState = () => (
  <div style={{
    maxWidth: 600, margin: '60px auto',
    padding: '32px 36px',
    background: '#fff', borderRadius: 10,
    border: '1px solid #FCA5A5',
    boxShadow: '0 8px 24px -8px rgba(0,0,0,0.12)',
  }}>
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 14 }}>
      <div style={{
        width: 36, height: 36, borderRadius: '50%',
        background: 'var(--error-bg)', border: '1px solid #FCA5A5',
        display: 'grid', placeItems: 'center', flexShrink: 0,
      }}>
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#DC2626" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>
        </svg>
      </div>
      <div style={{ flex: 1 }}>
        <div style={{
          display: 'inline-block', padding: '2px 8px', borderRadius: 4,
          background: 'var(--error-bg)', border: '1px solid #FECACA',
          fontFamily: 'JetBrains Mono, monospace', fontSize: 10, fontWeight: 700, color: '#991B1B',
          marginBottom: 8,
        }}>ERR-016</div>
        <div style={{ fontFamily: 'Inter', fontSize: 16, fontWeight: 700, color: 'var(--n-900)', marginBottom: 6 }}>
          명세서 생성에 실패했습니다
        </div>
        <div style={{ fontSize: 12.5, color: 'var(--n-700)', lineHeight: 1.6, marginBottom: 14 }}>
          PDF 렌더링 워커가 응답하지 않습니다 (timeout 30s · 재시도 3회 실패).
          잠시 후 다시 시도하거나, CSV 형식으로 먼저 다운로드하세요.
        </div>
        <div style={{
          padding: '10px 12px',
          background: 'var(--n-050)', border: '1px solid var(--n-200)', borderRadius: 6,
          fontFamily: 'JetBrains Mono, monospace', fontSize: 10.5, color: 'var(--n-700)',
          marginBottom: 16,
        }}>
          <div style={{ color: 'var(--n-500)', fontSize: 9.5, marginBottom: 3, fontWeight: 700 }}>RUN ID</div>
          <div>job-stmt-2026-04-22-1408-0048 · worker-pdf-04 · ECONNRESET</div>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <button style={{ padding: '8px 14px', background: 'var(--primary)', border: 'none', borderRadius: 6, color: '#fff', fontFamily: 'Inter', fontSize: 12.5, fontWeight: 700, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6 }}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg>
            다시 시도
          </button>
          <button style={{ padding: '8px 14px', background: '#fff', border: '1px solid var(--n-300)', borderRadius: 6, color: 'var(--n-700)', fontFamily: 'Inter', fontSize: 12.5, fontWeight: 600, cursor: 'pointer' }}>
            CSV로 다운로드
          </button>
          <button style={{ padding: '8px 14px', background: '#fff', border: '1px solid var(--n-300)', borderRadius: 6, color: 'var(--n-700)', fontFamily: 'Inter', fontSize: 12.5, fontWeight: 600, cursor: 'pointer' }}>
            지원팀 문의
          </button>
        </div>
      </div>
    </div>
  </div>
);

const StatementIssueFrame = ({ variant }) => (
  <AdminLayout activeId="settle">
    <div style={{ filter: 'blur(1.5px)', pointerEvents: 'none', opacity: 0.85 }}>
      <SettlementPage variant="normal"/>
    </div>
    <StatementIssueModal variant={variant}/>
  </AdminLayout>
);

Object.assign(window, { StatementIssueModal, StatementIssueFrame });
