// screens-money.jsx — Finance / Payments (审批中心) / Audit (审计日志)
// Wired to live admin endpoints via window.NebulaAdmin.{adminFetch, useAdminPoll}.
//
// Exports: FinanceScreen, PaymentsScreen, AuditScreen, MarketingScreen.
//   - FinanceScreen: /api/finance/flow + /api/pool/heatmap + wallet adjust modal.
//   - PaymentsScreen: /api/approvals with type tabs (all / withdraw / layout).
//   - AuditScreen: /api/audit + /api/admin/events/recent.
//   - MarketingScreen: unchanged from earlier mock (kept intact below).

const _adminFetch  = window.NebulaAdmin.adminFetch;
const _useAdminPoll = window.NebulaAdmin.useAdminPoll;

// ─── helpers ────────────────────────────────────────────────────────────────
function _fmtTime(ts) {
  if (!ts) return '—';
  try {
    const d = new Date(ts);
    if (isNaN(d.getTime())) return ts;
    return d.toLocaleString('zh-CN', { hour12: false });
  } catch (e) { return ts; }
}
function _fmtTimeShort(ts) {
  if (!ts) return '—';
  try {
    const d = new Date(ts);
    if (isNaN(d.getTime())) return ts;
    const hh = String(d.getHours()).padStart(2, '0');
    const mm = String(d.getMinutes()).padStart(2, '0');
    const ss = String(d.getSeconds()).padStart(2, '0');
    return `${hh}:${mm}:${ss}`;
  } catch (e) { return ts; }
}
function _entryTagFor(type) {
  switch (type) {
    case 'deposit': return 'accent';
    case 'withdraw': return 'warning';
    case 'bet': return 'outline';
    case 'win':
    case 'refund': return 'info';
    case 'adjust':
    case 'bonus': return 'danger';
    default: return 'outline';
  }
}
function _typeLabel(type, t) {
  const tx = (t && t.tx) ? t.tx : ((zh) => zh);
  const map = {
    deposit: tx('充值','Deposit'), withdraw: tx('提现','Withdraw'),
    bet: tx('投注','Bet'), win: tx('中奖','Win'),
    refund: tx('退款','Refund'), adjust: tx('调账','Adjust'),
    bonus: tx('奖励','Bonus'),
  };
  return map[type] || type || '—';
}

// ─────────────────────────────────────────────────────────────────────────────
// 11 FINANCE — live ledger + pool heatmap + wallet adjust
// ─────────────────────────────────────────────────────────────────────────────
function FinanceScreen({ t, push }) {
  const [flow]     = _useAdminPoll('/api/finance/flow', 8000);
  const [heatmap]  = _useAdminPoll('/api/pool/heatmap', 8000);
  const [search, setSearch] = React.useState('');
  const [bucket, setBucket] = React.useState('today'); // today | week | month
  const [adjustOpen, setAdjustOpen] = React.useState(false);

  const b = (flow && flow[bucket]) || { deposit: 0, withdraw: 0, bet: 0, payout: 0, adjust: 0 };
  const net = (b.deposit || 0) - (b.withdraw || 0) + (b.payout || 0) - (b.bet || 0);
  const entries = (flow && flow.recent_entries) || [];

  const filtered = entries.filter(e => {
    if (!search) return true;
    const q = search.toLowerCase();
    return (
      (e.user_id || '').toLowerCase().includes(q) ||
      (e.type || '').toLowerCase().includes(q) ||
      (e.ref || '').toLowerCase().includes(q) ||
      (e.note || '').toLowerCase().includes(q)
    );
  });

  // 24h bucketed deposit/withdraw series from recent_entries (coarse, demo viz).
  const series24h = React.useMemo(() => {
    const dep = new Array(24).fill(0);
    const wd  = new Array(24).fill(0);
    const now = Date.now();
    for (const e of entries) {
      const ts = e.ts ? new Date(e.ts).getTime() : 0;
      if (!ts) continue;
      const ageH = (now - ts) / 3600000;
      if (ageH < 0 || ageH >= 24) continue;
      const idx = 23 - Math.floor(ageH);
      const amt = Math.abs(Number(e.amount) || 0);
      if (e.type === 'deposit') dep[idx] += amt;
      else if (e.type === 'withdraw') wd[idx] += amt;
    }
    return { dep, wd };
  }, [entries]);

  return (
    <div className="stack">
      <div className="page-h">
        <div>
          <h1>{t.p_finance}</h1>
          <div className="sub">{t.tx('钱包账本 · 充值 / 提现 / 调账 · 全留痕 · 实时','Wallet ledger · Deposit / Withdraw / Adjust · Fully audited · Real-time')}</div>
        </div>
        <div className="actions">
          <button className="btn btn-sm"><Icons.download /> {t.export}</button>
          <button className="btn btn-sm" onClick={() => push(t.tx('对账任务已触发','Reconciliation job triggered'))}><Icons.refresh /> {t.tx('对账','Reconcile')}</button>
          <button className="btn btn-pri btn-sm" onClick={() => setAdjustOpen(true)}><Icons.plus /> {t.tx('调整钱包','Adjust Wallet')}</button>
        </div>
      </div>

      {/* Bucket switcher */}
      <div className="tabs">
        {[['today',t.tx('今日','Today')],['week',t.tx('本周','This Week')],['month',t.tx('本月','This Month')]].map(([k,l]) => (
          <div key={k} className={'tab' + (bucket === k ? ' active' : '')} onClick={() => setBucket(k)}>{l}</div>
        ))}
      </div>

      <div className="row-4">
        <KPI label={`${bucket === 'today' ? t.tx('今日','Today') : bucket === 'week' ? t.tx('本周','This Week') : t.tx('本月','This Month')} ${t.tx('充值','Deposit')}`} value={fmtCN(b.deposit)} spark={<Sparkline data={series24h.dep.length ? series24h.dep : [1,1]} w={100} h={24} />} />
        <KPI label={t.tx('提现','Withdraw')} value={fmtCN(b.withdraw)} spark={<Sparkline data={series24h.wd.length ? series24h.wd : [1,1]} w={100} h={24} stroke="oklch(0.65 0.14 30)" />} />
        <KPI label={t.tx('投注 / 派彩','Bet / Payout')} value={`${fmtCN(b.bet)} / ${fmtCN(b.payout)}`} spark={<MiniBars data={[b.bet || 0.1, b.payout || 0.1]} w={100} h={24} />} />
        <KPI label={t.tx('净流入','Net Inflow')} value={fmtCN(net)} delta={net >= 0 ? '↑' : '↓'} up={net >= 0} spark={<Sparkline data={[0, net]} w={100} h={24} stroke={net >= 0 ? 'oklch(0.6 0.16 145)' : 'oklch(0.65 0.18 30)'} />} />
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1.7fr 1fr', gap: 16 }}>
        {/* Recent ledger */}
        <div className="card">
          <div className="filter-bar">
            <span className="chip active">{t.tx('最近 50 条','Latest 50')}</span>
            <span className="text-muted" style={{ fontSize: 11.5 }}>{t.tx('共','Total')} {filtered.length}</span>
            <div style={{ flex: 1 }} />
            <input className="input" placeholder={t.tx('搜索 user_id / type / ref / note','Search user_id / type / ref / note')}
                   value={search} onChange={(e) => setSearch(e.target.value)}
                   style={{ width: 240, height: 26, fontSize: 12 }} />
          </div>
          <div className="tbl-scroll">
          <table className="tbl tbl-stack">
            <thead><tr>
              <th>{t.tx('时间','Time')}</th><th>{t.tx('类型','Type')}</th><th>{t.tx('用户','User')}</th>
              <th className="right">{t.tx('变动','Change')}</th><th>{t.tx('单号 / 备注','Ref / Note')}</th>
            </tr></thead>
            <tbody>
              {filtered.length === 0 ? (
                <tr><td colSpan={5} className="muted" style={{ textAlign: 'center', padding: 20 }}>{t.tx('暂无流水','No transactions')}</td></tr>
              ) : filtered.map((e) => {
                const amt = Number(e.amount) || 0;
                return (
                  <tr key={e.id}>
                    <td data-label={t.tx('时间','Time')} className="text-mono muted" style={{ fontSize: 11 }}>{_fmtTimeShort(e.ts)}</td>
                    <td data-label={t.tx('类型','Type')}><span className={`badge ${_entryTagFor(e.type)}`}>{_typeLabel(e.type, t)}</span></td>
                    <td data-label={t.tx('用户','User')}>
                      <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
                        <Avatar name={e.user_id || '?'} size={20} />
                        <span style={{ fontWeight: 500 }}>{e.user_id || '—'}</span>
                      </div>
                    </td>
                    <td data-label={t.tx('变动','Change')} className="right tabular" style={{ color: amt > 0 ? 'var(--success)' : 'var(--danger)', fontWeight: 500 }}>
                      {amt > 0 ? '+' : ''}{fmtCN(amt)}
                    </td>
                    <td data-label={t.tx('单号 / 备注','Ref / Note')} className="text-mono muted" style={{ fontSize: 11 }}>
                      {e.ref || '—'}{e.note ? <span className="text-faint"> · {e.note}</span> : null}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
          </div>
        </div>

        {/* Pool heatmap mini */}
        <div className="card">
          <div className="card-h">
            <h3>{t.tx('奖池分布 · 当前期','Pool Distribution · Current Period')}</h3>
            <span className="meta">{heatmap ? `${heatmap.lottery || '—'} · ${heatmap.current_period || '—'}` : t.tx('加载中','Loading')}</span>
          </div>
          <div style={{ padding: '12px 16px' }}>
            <div className="text-muted" style={{ fontSize: 11, marginBottom: 8 }}>
              {t.tx('失衡分数：','Imbalance Score: ')}<span className="tabular" style={{ color: heatmap && heatmap.imbalance_score >= 0.5 ? 'var(--danger)' : 'var(--text)' }}>
                {heatmap ? (heatmap.imbalance_score || 0).toFixed(2) : '—'}
              </span>
            </div>
            <PoolBars rows={(heatmap && heatmap.by_play) || []} t={t} />
            <div className="divider" />
            <div className="text-muted" style={{ fontSize: 11, marginBottom: 6 }}>{t.tx('用户集中度','User Concentration')}（Top {Math.min(5, ((heatmap && heatmap.by_user_concentration) || []).length)}）</div>
            <div className="tbl-scroll">
            <table className="tbl tbl-stack" style={{ marginTop: 0 }}>
              <tbody>
                {((heatmap && heatmap.by_user_concentration) || []).slice(0, 5).map((u, i) => (
                  <tr key={u.user_id || i}>
                    <td data-label={t.tx('用户','User')} style={{ fontSize: 11 }}>
                      <Avatar name={u.user_id} size={18} />
                      <span style={{ marginLeft: 6 }}>{u.user_id}</span>
                    </td>
                    <td data-label={t.tx('投注','Stake')} className="right tabular" style={{ fontSize: 11 }}>{fmtCN(u.stake)}</td>
                  </tr>
                ))}
                {((heatmap && heatmap.by_user_concentration) || []).length === 0 && (
                  <tr><td className="muted" style={{ textAlign: 'center', padding: 12 }}>{t.tx('暂无投注','No bets')}</td></tr>
                )}
              </tbody>
            </table>
            </div>
          </div>
        </div>
      </div>

      {/* 24h flow trend */}
      <div className="card">
        <div className="card-h">
          <h3>{t.tx('24h 充提走势（基于最近账本聚合）','24h Deposit/Withdraw Trend (Aggregated from recent ledger)')}</h3>
          <span className="meta">
            <span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: 2, background: 'var(--accent)', marginRight: 4 }} /> {t.tx('充值','Deposit')}
            <span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: 2, background: 'oklch(0.65 0.14 30)', marginLeft: 10, marginRight: 4 }} /> {t.tx('提现','Withdraw')}
          </span>
        </div>
        <div style={{ padding: 16, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
          <div>
            <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>{t.tx('充值','Deposit')}</div>
            <Sparkline data={series24h.dep.length ? series24h.dep : [0, 0]} w={400} h={56} />
          </div>
          <div>
            <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>{t.tx('提现','Withdraw')}</div>
            <Sparkline data={series24h.wd.length ? series24h.wd : [0, 0]} w={400} h={56} stroke="oklch(0.65 0.14 30)" />
          </div>
        </div>
      </div>

      {adjustOpen && <WalletAdjustModal onClose={() => setAdjustOpen(false)} t={t} push={push} />}
    </div>
  );
}

function PoolBars({ rows, t }) {
  const max = rows.reduce((m, r) => Math.max(m, r.total_stake || 0), 0) || 1;
  if (rows.length === 0) {
    return <div className="muted" style={{ fontSize: 12, padding: '12px 0' }}>{(t && t.tx ? t.tx : ((zh) => zh))('当前期暂无投注','No bets in current period')}</div>;
  }
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {rows.slice(0, 8).map((r) => (
        <div key={r.play_id} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11 }}>
          <span style={{ width: 70, color: 'var(--text-muted)' }}>{r.play_id}</span>
          <span className="barmini" style={{ flex: 1 }}>
            <i style={{ width: `${Math.max(2, (r.total_stake / max) * 100)}%` }} />
          </span>
          <span className="tabular" style={{ minWidth: 70, textAlign: 'right' }}>{fmtCN(r.total_stake)}</span>
          <span className="text-faint tabular" style={{ minWidth: 30, textAlign: 'right' }}>×{r.bets_count}</span>
        </div>
      ))}
    </div>
  );
}

function WalletAdjustModal({ onClose, t, push }) {
  const [userId, setUserId] = React.useState('');
  const [amount, setAmount] = React.useState('');
  const [note, setNote] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState('');

  const submit = async () => {
    setErr('');
    const amt = parseFloat(amount);
    if (!userId.trim()) { setErr(t.tx('请输入 user_id','Please enter user_id')); return; }
    if (!isFinite(amt) || amt === 0) { setErr(t.tx('金额必须是非零数字（正充负扣）','Amount must be a non-zero number (positive credit / negative debit)')); return; }
    if (amt > 1_000_000 || amt < -1_000_000) { setErr(t.tx('单次调整额度 ≤ ¥1,000,000','Per-adjustment limit ≤ ¥1,000,000')); return; }
    setBusy(true);
    try {
      const r = await _adminFetch(`/api/wallet/${encodeURIComponent(userId.trim())}/adjust`, {
        method: 'POST',
        body: JSON.stringify({ amount: amt, note: note.trim() }),
      });
      const newBal = r && r.wallet ? r.wallet.balance : null;
      push(`${t.tx('已调整','Adjusted')} ${userId} · ${amt > 0 ? '+' : ''}${fmtCN(amt)}${newBal != null ? ` · ${t.tx('新余额','New balance')} ${fmtCN(newBal)}` : ''}`);
      onClose();
    } catch (e) {
      setErr((e && e.body && e.body.error) || (e && e.message) || t.tx('调整失败','Adjustment failed'));
    } finally {
      setBusy(false);
    }
  };

  return (
    <Modal open={true} onClose={onClose} title={t.tx('调整钱包余额','Adjust Wallet Balance')} width={460}
           footer={<>
             <button className="btn btn-sm" onClick={onClose} disabled={busy}>{t.cancel}</button>
             <button className="btn btn-pri btn-sm" onClick={submit} disabled={busy}>{busy ? t.tx('提交中…','Submitting…') : t.tx('确认调整','Confirm Adjustment')}</button>
           </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <_Field label={t.tx('用户 ID','User ID')}>
          <input className="input" value={userId} onChange={(e) => setUserId(e.target.value)} placeholder={t.tx('如 U-1024','e.g. U-1024')} autoFocus />
        </_Field>
        <_Field label={t.tx('金额（正充 / 负扣，¥）','Amount (positive credit / negative debit, ¥)')}>
          <input className="input" value={amount} onChange={(e) => setAmount(e.target.value)} placeholder={t.tx('例如 100 或 -50','e.g. 100 or -50')} inputMode="decimal" />
        </_Field>
        <_Field label={t.tx('备注','Note')}>
          <input className="input" value={note} onChange={(e) => setNote(e.target.value)} placeholder={t.tx('调账原因，会写入 ledger.note','Reason for adjustment, written to ledger.note')} />
        </_Field>
        {err && <div style={{ color: 'var(--danger)', fontSize: 12 }}>{err}</div>}
        <div className="text-faint" style={{ fontSize: 11 }}>
          {t.tx('调用','Calls')} <span className="text-mono">POST /api/wallet/{'{userId}'}/adjust</span> · {t.tx('写入 ledger（type=adjust）并触发审计。','Writes ledger (type=adjust) and triggers audit.')}
        </div>
      </div>
    </Modal>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// 12 PAYMENTS — 审批中心 (withdraw + layout)
// ─────────────────────────────────────────────────────────────────────────────
// PaymentsScreen — top-level tab strip: existing 审批中心 stays the default tab so
// no prior demo flow is lost. Compliance tabs (channel routing / reconciliation /
// suspicious queue / dual-stage withdraw approval) live as sibling sub-screens.
function PaymentsScreen({ t, push }) {
  const [section, setSection] = React.useState('approvals'); // approvals | channels | reconcile | suspicious | dual
  const sections = [
    ['approvals',  t.tx('审批中心',  'Approvals')],
    ['channels',   t.tx('通道路由',  'Channels')],
    ['reconcile',  t.tx('对账',      'Reconcile')],
    ['suspicious', t.tx('可疑交易',  'Suspicious')],
    ['dual',       t.tx('提现审核',  'Withdraw Approval')],
  ];
  return (
    <div className="stack">
      <div className="page-h">
        <div>
          <h1>{t.p_payments}</h1>
          <div className="sub">{t.tx('合规与多通道路由 · KYC / 双签 / 对账 / 可疑交易','Compliance & multi-channel routing')}</div>
        </div>
      </div>
      <div className="tabs">
        {sections.map(([k, l]) => (
          <div key={k} className={'tab' + (section === k ? ' active' : '')} onClick={() => setSection(k)}>{l}</div>
        ))}
      </div>
      {section === 'approvals'  && <PaymentsApprovalsPanel t={t} push={push} />}
      {section === 'channels'   && <ChannelRoutingPanel    t={t} push={push} />}
      {section === 'reconcile'  && <ReconcilePanel         t={t} push={push} />}
      {section === 'suspicious' && <SuspiciousPanel        t={t} push={push} />}
      {section === 'dual'       && <WithdrawApprovalPanel  t={t} push={push} />}
    </div>
  );
}

// PaymentsApprovalsPanel — extracted from the original PaymentsScreen so the
// existing single-stage approval workflow remains untouched.
function PaymentsApprovalsPanel({ t, push }) {
  const [data, , reload] = useApprovals();
  const [tab, setTab] = React.useState('all'); // all | withdraw | layout
  const [confirm, setConfirm] = React.useState(null); // {ap, action}

  const all = (data && data.approvals) || [];
  const list = all.filter(a => tab === 'all' ? true : a.type === tab);
  const counts = {
    all: all.length,
    withdraw: all.filter(a => a.type === 'withdraw').length,
    layout: all.filter(a => a.type === 'layout').length,
  };

  const doAction = async () => {
    if (!confirm) return;
    const { ap, action } = confirm;
    try {
      await _adminFetch(`/api/approvals/${ap.id}/${action}`, { method: 'POST' });
      push(`${ap.id} ${action === 'approve' ? t.tx('已通过','Approved') : t.tx('已驳回','Rejected')}`);
      setConfirm(null);
      if (reload) reload();
    } catch (e) {
      push(`${t.tx('操作失败：','Operation failed: ')}${(e && e.body && e.body.error) || (e && e.message) || 'unknown'}`);
      setConfirm(null);
    }
  };

  return (
    <div className="stack">
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div className="sub">{t.tx('审批中心 · 提现 / 装修发布 · 共','Approvals · Withdraw / Layout publish · Total')} {counts.all} {t.tx('待办','pending')}</div>
        <button className="btn btn-sm" onClick={() => reload && reload()}><Icons.refresh /> {t.tx('刷新','Refresh')}</button>
      </div>

      <div className="tabs">
        {[['all', `${t.tx('全部','All')} ${counts.all}`], ['withdraw', `${t.tx('提现','Withdraw')} ${counts.withdraw}`], ['layout', `${t.tx('装修','Layout')} ${counts.layout}`]].map(([k, l]) => (
          <div key={k} className={'tab' + (tab === k ? ' active' : '')} onClick={() => setTab(k)}>{l}</div>
        ))}
      </div>

      <div className="card">
        <div className="tbl-scroll">
        <table className="tbl tbl-stack">
          <thead><tr>
            <th>{t.tx('单号 / 类型','Ref / Type')}</th>
            <th>{t.tx('目标','Target')}</th>
            <th>{t.tx('申请人','Applicant')}</th>
            <th className="right">{t.tx('金额 / 内容','Amount / Content')}</th>
            <th>{t.tx('优先级','Priority')}</th>
            <th>{t.tx('风险','Risk')}</th>
            <th>{t.tx('创建时间','Created')}</th>
            <th>{t.tx('状态','Status')}</th>
            <th></th>
          </tr></thead>
          <tbody>
            {list.length === 0 ? (
              <tr><td colSpan={9} className="muted" style={{ textAlign: 'center', padding: 24 }}>{t.tx('暂无审批','No approvals')}</td></tr>
            ) : list.map((a) => {
              const snap = a.snapshot || {};
              const isW = a.type === 'withdraw';
              return (
                <tr key={a.id}>
                  <td data-label={t.tx('单号 / 类型','Ref / Type')}>
                    <div className="text-mono" style={{ fontSize: 11 }}>{a.id}</div>
                    <span className={'badge ' + (isW ? 'warning' : 'info')}>{isW ? t.tx('提现','Withdraw') : t.tx('装修','Layout')}</span>
                  </td>
                  <td data-label={t.tx('目标','Target')} style={{ fontSize: 12 }}>{a.target || '—'}</td>
                  <td data-label={t.tx('申请人','Applicant')}>
                    <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
                      <Avatar name={a.who || a.user_id || '?'} size={20} />
                      <div>
                        <div style={{ fontWeight: 500, fontSize: 12 }}>{a.who || '—'}</div>
                        {a.user_id && <div className="text-faint text-mono" style={{ fontSize: 10 }}>{a.user_id}</div>}
                      </div>
                    </div>
                  </td>
                  <td data-label={t.tx('金额 / 内容','Amount / Content')} className="right tabular" style={{ fontSize: 12 }}>
                    {isW ? (
                      <>
                        <div style={{ fontWeight: 500 }}>{fmtCN(snap.amount)}</div>
                        <div className="text-faint" style={{ fontSize: 10 }}>
                          {t.tx('手续费','Fee')} {fmtCN(snap.fee || 0)} · {t.tx('实付','Net')} {fmtCN(snap.total || snap.amount)}
                        </div>
                      </>
                    ) : (
                      <div className="muted text-mono" style={{ fontSize: 10 }}>{snap.page || '—'}</div>
                    )}
                  </td>
                  <td data-label={t.tx('优先级','Priority')}>
                    <span className={'badge ' + (a.priority === 'high' ? 'danger' : a.priority === 'low' ? 'outline' : 'warning')}>
                      {a.priority || 'mid'}
                    </span>
                  </td>
                  <td data-label={t.tx('风险','Risk')}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                      <RiskDot score={Number(a.risk) || 0} />
                      <span className="tabular" style={{ fontSize: 11 }}>{a.risk != null ? a.risk : '—'}</span>
                    </div>
                  </td>
                  <td data-label={t.tx('创建时间','Created')} className="text-mono muted" style={{ fontSize: 11 }}>{_fmtTime(a.created_at)}</td>
                  <td data-label={t.tx('状态','Status')}><StatusBadge status={a.status} t={t} /></td>
                  <td data-label={t.tx('操作', 'Actions')} className="tbl-actions">
                    {a.status === 'pending' ? <>
                      <button className="btn btn-xs btn-ghost" onClick={() => setConfirm({ ap: a, action: 'reject' })}>{t.reject}</button>
                      <button className="btn btn-xs btn-pri" onClick={() => setConfirm({ ap: a, action: 'approve' })}>{t.approve}</button>
                    </> : <button className="btn btn-xs btn-ghost" disabled>{t.detail}</button>}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        </div>
      </div>

      {confirm && (
        <Modal open={true} onClose={() => setConfirm(null)} title={confirm.action === 'approve' ? t.tx('确认通过','Confirm Approve') : t.tx('确认驳回','Confirm Reject')} width={420}
               footer={<>
                 <button className="btn btn-sm" onClick={() => setConfirm(null)}>{t.cancel}</button>
                 <button className={'btn btn-sm ' + (confirm.action === 'approve' ? 'btn-pri' : '')} onClick={doAction}>
                   {confirm.action === 'approve' ? t.approve : t.reject}
                 </button>
               </>}>
          <div style={{ fontSize: 13 }}>
            {t.tx('将','Will ')}{confirm.action === 'approve' ? t.tx('通过','approve') : t.tx('驳回','reject')} <span className="text-mono">{confirm.ap.id}</span>
            （{confirm.ap.type === 'withdraw' ? t.tx('提现','Withdraw') : t.tx('装修','Layout')} · {confirm.ap.target || '—'}）
          </div>
          {confirm.ap.type === 'withdraw' && confirm.ap.snapshot && (
            <div className="text-muted" style={{ fontSize: 12, marginTop: 8 }}>
              {t.tx('金额','Amount')} {fmtCN(confirm.ap.snapshot.amount)} · {t.tx('手续费','Fee')} {fmtCN(confirm.ap.snapshot.fee || 0)} · {t.tx('实付','Net')} {fmtCN(confirm.ap.snapshot.total || confirm.ap.snapshot.amount)}
            </div>
          )}
        </Modal>
      )}
    </div>
  );
}

// useApprovals — poll wrapper that also exposes a manual reload for post-action refresh.
function useApprovals() {
  const [tick, setTick] = React.useState(0);
  const [data, err] = _useAdminPoll('/api/approvals' + (tick ? `?_=${tick}` : ''), 6000);
  return [data, err, () => setTick(Date.now())];
}

// ─────────────────────────────────────────────────────────────────────────────
// PAYMENTS · CHANNEL ROUTING — 通道路由
// ─────────────────────────────────────────────────────────────────────────────
function ChannelRoutingPanel({ t, push }) {
  const [data, , reload] = (() => {
    const [tick, setTick] = React.useState(0);
    const [d] = _useAdminPoll('/api/admin/payment-channels' + (tick ? `?_=${tick}` : ''), 12000);
    return [d, null, () => setTick(Date.now())];
  })();
  const rows = (data && data.channels) || [];
  const [edit, setEdit] = React.useState(null); // {id, patch}

  const onChange = (id, patch) => {
    setEdit((cur) => ({ id, patch: { ...(cur && cur.id === id ? cur.patch : {}), ...patch } }));
  };
  const save = async (id) => {
    try {
      await _adminFetch(`/api/admin/payment-channels/${id}`, { method: 'PUT', body: JSON.stringify(edit.patch) });
      push(t.tx('通道更新成功','Channel updated'));
      setEdit(null);
      reload();
    } catch (e) {
      push(`${t.tx('更新失败：','Update failed: ')}${(e && e.body && e.body.error) || (e && e.message) || 'unknown'}`);
    }
  };

  return (
    <div className="card">
      <div className="tbl-scroll">
      <table className="tbl tbl-stack">
        <thead><tr>
          <th>{t.tx('通道','Channel')}</th>
          <th>{t.tx('类型','Kind')}</th>
          <th className="right">{t.tx('费率','Fee')}</th>
          <th className="right">{t.tx('成功率','Success')}</th>
          <th className="right">{t.tx('日限额','Daily Limit')}</th>
          <th className="right">{t.tx('今日流水','Today')}</th>
          <th className="right">{t.tx('优先级','Priority')}</th>
          <th>{t.tx('启用','Active')}</th>
          <th></th>
        </tr></thead>
        <tbody>
          {rows.length === 0 ? (
            <tr><td colSpan={9} className="muted" style={{ textAlign: 'center', padding: 24 }}>{t.tx('暂无通道','No channels')}</td></tr>
          ) : rows.map((c) => {
            const isEditing = edit && edit.id === c.id;
            const v = isEditing ? { ...c, ...edit.patch } : c;
            return (
              <tr key={c.id}>
                <td data-label={t.tx('通道','Channel')}>
                  <div style={{ fontWeight: 500, fontSize: 13 }}>{c.name}</div>
                  <div className="text-faint text-mono" style={{ fontSize: 10 }}>{c.id}</div>
                </td>
                <td data-label={t.tx('类型','Kind')}><span className="badge outline">{c.kind}</span></td>
                <td data-label={t.tx('费率','Fee')} className="right tabular">
                  <input className="input" style={{ width: 70, textAlign: 'right' }} type="number" step="0.001"
                         value={v.fee_rate} onChange={(e) => onChange(c.id, { fee_rate: Number(e.target.value) })} />
                </td>
                <td data-label={t.tx('成功率','Success')} className="right tabular">
                  <input className="input" style={{ width: 70, textAlign: 'right' }} type="number" step="0.01" min="0" max="1"
                         value={v.success_rate} onChange={(e) => onChange(c.id, { success_rate: Number(e.target.value) })} />
                </td>
                <td data-label={t.tx('日限额','Daily Limit')} className="right tabular">
                  <input className="input" style={{ width: 100, textAlign: 'right' }} type="number" step="1000"
                         value={v.daily_limit} onChange={(e) => onChange(c.id, { daily_limit: Number(e.target.value) })} />
                </td>
                <td data-label={t.tx('今日流水','Today')} className="right tabular">{fmtCN(c.today_volume || 0)}</td>
                <td data-label={t.tx('优先级','Priority')} className="right tabular">
                  <input className="input" style={{ width: 60, textAlign: 'right' }} type="number"
                         value={v.priority} onChange={(e) => onChange(c.id, { priority: Number(e.target.value) })} />
                </td>
                <td data-label={t.tx('启用','Active')}>
                  <label style={{ display: 'inline-flex', gap: 4, alignItems: 'center', cursor: 'pointer' }}>
                    <input type="checkbox" checked={!!v.active} onChange={(e) => onChange(c.id, { active: e.target.checked })} />
                    <span className="text-muted" style={{ fontSize: 11 }}>{v.active ? t.tx('启用','On') : t.tx('停用','Off')}</span>
                  </label>
                </td>
                <td data-label={t.tx('操作', 'Actions')} className="tbl-actions">
                  {isEditing ? (
                    <>
                      <button className="btn btn-xs btn-ghost" onClick={() => setEdit(null)}>{t.cancel}</button>
                      <button className="btn btn-xs btn-pri" onClick={() => save(c.id)}>{t.save}</button>
                    </>
                  ) : <span className="text-faint" style={{ fontSize: 10 }}>{t.tx('修改即可保存','Edit to save')}</span>}
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// PAYMENTS · RECONCILE — 对账
// ─────────────────────────────────────────────────────────────────────────────
function ReconcilePanel({ t, push }) {
  const [date, setDate] = React.useState(() => new Date().toISOString().slice(0, 10));
  const [tick, setTick] = React.useState(0);
  const [data] = _useAdminPoll(`/api/admin/reconcile?date=${date}&_=${tick}`, 30000);
  const rows = (data && data.rows) || [];

  const runReconcile = async () => {
    try {
      await _adminFetch(`/api/admin/reconcile/run?date=${date}`, { method: 'POST' });
      push(t.tx('对账已执行','Reconcile run'));
      setTick(Date.now());
    } catch (e) {
      push(`${t.tx('对账失败：','Run failed: ')}${(e && e.body && e.body.error) || (e && e.message) || 'unknown'}`);
    }
  };

  const totals = rows.reduce((acc, r) => ({
    ledger: acc.ledger + (r.ledger_total || 0),
    channel: acc.channel + (r.channel_total || 0),
    diff: acc.diff + (r.diff || 0),
    mismatch: acc.mismatch + (r.status === 'mismatch' ? 1 : 0),
  }), { ledger: 0, channel: 0, diff: 0, mismatch: 0 });

  return (
    <div className="stack">
      <div className="card" style={{ display: 'flex', gap: 12, alignItems: 'center', flexWrap: 'wrap', padding: 12 }}>
        <span className="text-muted" style={{ fontSize: 11 }}>{t.tx('对账日期','Date')}</span>
        <DateRangePicker t={t} mode="single" date={date} onChange={(d) => setDate(d)} size="sm" />
        <button className="btn btn-sm btn-pri" onClick={runReconcile}>{t.tx('手动跑对账','Run Reconcile')}</button>
        <div style={{ flex: 1 }} />
        <div className="text-muted" style={{ fontSize: 11 }}>
          {t.tx('账本合计','Ledger')}: <b className="tabular">{fmtCN(totals.ledger)}</b> ·
          &nbsp;{t.tx('通道合计','Channel')}: <b className="tabular">{fmtCN(totals.channel)}</b> ·
          &nbsp;{t.tx('差额','Diff')}: <b className="tabular" style={{ color: Math.abs(totals.diff) > 0.01 ? 'var(--warning)' : 'inherit' }}>{fmtCN(totals.diff)}</b> ·
          &nbsp;{t.tx('差异行','Mismatch')}: <b>{totals.mismatch}</b>
        </div>
      </div>
      <div className="card">
        <div className="tbl-scroll">
        <table className="tbl tbl-stack">
          <thead><tr>
            <th>{t.tx('通道','Channel')}</th>
            <th className="right">{t.tx('账本合计','Ledger Total')}</th>
            <th className="right">{t.tx('通道合计','Channel Total')}</th>
            <th className="right">{t.tx('差额','Diff')}</th>
            <th>{t.tx('状态','Status')}</th>
            <th>{t.tx('备注','Notes')}</th>
            <th>{t.tx('对账时间','Reconciled')}</th>
          </tr></thead>
          <tbody>
            {rows.length === 0 ? (
              <tr><td colSpan={7} className="muted" style={{ textAlign: 'center', padding: 24 }}>{t.tx('当日暂无对账记录，可点击「手动跑对账」生成','No reconcile rows — click Run Reconcile')}</td></tr>
            ) : rows.map((r) => (
              <tr key={r.channel_id}>
                <td data-label={t.tx('通道','Channel')} className="text-mono" style={{ fontSize: 11 }}>{r.channel_id}</td>
                <td data-label={t.tx('账本合计','Ledger Total')} className="right tabular">{fmtCN(r.ledger_total)}</td>
                <td data-label={t.tx('通道合计','Channel Total')} className="right tabular">{fmtCN(r.channel_total)}</td>
                <td data-label={t.tx('差额','Diff')} className="right tabular" style={{ color: Math.abs(r.diff) > 0.01 ? 'var(--warning)' : 'inherit' }}>{fmtCN(r.diff)}</td>
                <td data-label={t.tx('状态','Status')}><span className={'badge ' + (r.status === 'ok' ? 'info' : 'warning')}>{r.status}</span></td>
                <td data-label={t.tx('备注','Notes')} className="text-faint" style={{ fontSize: 11 }}>{r.notes || '—'}</td>
                <td data-label={t.tx('对账时间','Reconciled')} className="text-mono muted" style={{ fontSize: 11 }}>{_fmtTime(r.reconciled_at)}</td>
              </tr>
            ))}
          </tbody>
        </table>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// PAYMENTS · SUSPICIOUS — 可疑交易
// ─────────────────────────────────────────────────────────────────────────────
function SuspiciousPanel({ t, push }) {
  const [tick, setTick] = React.useState(0);
  const [data] = _useAdminPoll(`/api/admin/suspicious?_=${tick}`, 10000);
  const items = (data && data.items) || [];

  const resolve = async (id, resolution) => {
    try {
      await _adminFetch(`/api/admin/suspicious/${id}/resolve`, { method: 'POST', body: JSON.stringify({ resolution, notes: '' }) });
      push(t.tx('已处置','Resolved'));
      setTick(Date.now());
    } catch (e) {
      push(`${t.tx('处置失败：','Resolve failed: ')}${(e && e.body && e.body.error) || (e && e.message) || 'unknown'}`);
    }
  };

  const sevColor = (s) => s === 'high' ? 'danger' : s === 'low' ? 'outline' : 'warning';
  const reasonLabel = (r) => ({
    amount_anomaly: t.tx('金额异常','Amount anomaly'),
    velocity:       t.tx('频次异常','Velocity'),
    kyc_pending:    t.tx('KYC 未通过','KYC pending'),
    manual_review:  t.tx('人工标记','Manual review'),
  }[r] || r);

  return (
    <div className="card">
      <div className="tbl-scroll">
      <table className="tbl tbl-stack">
        <thead><tr>
          <th>{t.tx('订单 / 用户','Order / User')}</th>
          <th>{t.tx('原因','Reason')}</th>
          <th>{t.tx('严重程度','Severity')}</th>
          <th className="right">{t.tx('金额','Amount')}</th>
          <th>{t.tx('标记时间','Flagged')}</th>
          <th>{t.tx('处置','Resolution')}</th>
          <th></th>
        </tr></thead>
        <tbody>
          {items.length === 0 ? (
            <tr><td colSpan={7} className="muted" style={{ textAlign: 'center', padding: 24 }}>{t.tx('暂无可疑交易','No suspicious transactions')}</td></tr>
          ) : items.map((s) => (
            <tr key={s.id}>
              <td data-label={t.tx('订单 / 用户','Order / User')}>
                <div className="text-mono" style={{ fontSize: 11 }}>{s.order_id}</div>
                <div className="text-faint text-mono" style={{ fontSize: 10 }}>{s.user_id}</div>
              </td>
              <td data-label={t.tx('原因','Reason')}><span className="badge outline">{reasonLabel(s.reason)}</span></td>
              <td data-label={t.tx('严重程度','Severity')}><span className={'badge ' + sevColor(s.severity)}>{s.severity}</span></td>
              <td data-label={t.tx('金额','Amount')} className="right tabular">{fmtCN(s.amount)}</td>
              <td data-label={t.tx('标记时间','Flagged')} className="text-mono muted" style={{ fontSize: 11 }}>{_fmtTime(s.flagged_at)}</td>
              <td data-label={t.tx('处置','Resolution')}>
                {s.resolved_at ? (
                  <div>
                    <span className="badge info">{s.resolution}</span>
                    <div className="text-faint" style={{ fontSize: 10 }}>{s.reviewer} · {_fmtTime(s.resolved_at)}</div>
                  </div>
                ) : <span className="text-faint" style={{ fontSize: 11 }}>{t.tx('未处置','Open')}</span>}
              </td>
              <td data-label={t.tx('操作', 'Actions')} className="tbl-actions">
                {!s.resolved_at ? <>
                  <button className="btn btn-xs btn-ghost" onClick={() => resolve(s.id, 'released')}>{t.tx('放行','Release')}</button>
                  <button className="btn btn-xs btn-ghost" onClick={() => resolve(s.id, 'frozen')}>{t.tx('冻结','Freeze')}</button>
                  <button className="btn btn-xs" onClick={() => resolve(s.id, 'refunded')}>{t.tx('退款','Refund')}</button>
                </> : <span className="text-faint" style={{ fontSize: 10 }}>—</span>}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// PAYMENTS · DUAL-STAGE WITHDRAW APPROVAL — 提现审核
// ─────────────────────────────────────────────────────────────────────────────
function WithdrawApprovalPanel({ t, push }) {
  const [tick, setTick] = React.useState(0);
  const [data] = _useAdminPoll(`/api/admin/withdraws?_=${tick}`, 8000);
  const items = (data && data.items) || [];
  const me = (() => { try { return JSON.parse(localStorage.getItem('nebula.admin.user') || 'null'); } catch { return null; } })();
  const myName = (me && me.name) || '';

  const act = async (orderID, kind) => {
    try {
      if (kind === 'reject') {
        const reason = window.prompt(t.tx('驳回原因？','Reject reason?')) || '';
        await _adminFetch(`/api/admin/withdraws/${orderID}/reject`, { method: 'POST', body: JSON.stringify({ reason }) });
      } else {
        await _adminFetch(`/api/admin/withdraws/${orderID}/${kind}`, { method: 'POST' });
      }
      push(t.tx('操作成功','Done'));
      setTick(Date.now());
    } catch (e) {
      push(`${t.tx('操作失败：','Failed: ')}${(e && e.body && e.body.error) || (e && e.message) || 'unknown'}`);
    }
  };

  return (
    <div className="card">
      <div style={{ padding: '8px 12px', fontSize: 11 }} className="text-muted">
        {t.tx('两级审核：同一管理员不能同时担任一审与二审。','Dual approval: the same admin cannot run both stages on one order.')}
        {myName && <span style={{ marginLeft: 8 }}>{t.tx('当前管理员：','You: ')}<b>{myName}</b></span>}
      </div>
      <div className="tbl-scroll">
      <table className="tbl tbl-stack">
        <thead><tr>
          <th>{t.tx('订单 / 用户','Order / User')}</th>
          <th className="right">{t.tx('金额 / 手续费','Amount / Fee')}</th>
          <th>{t.tx('通道','Channel')}</th>
          <th>{t.tx('状态','Status')}</th>
          <th>{t.tx('一审','1st Approver')}</th>
          <th>{t.tx('二审','2nd Approver')}</th>
          <th>{t.tx('创建时间','Created')}</th>
          <th></th>
        </tr></thead>
        <tbody>
          {items.length === 0 ? (
            <tr><td colSpan={8} className="muted" style={{ textAlign: 'center', padding: 24 }}>{t.tx('无提现订单','No withdraw orders')}</td></tr>
          ) : items.map((o) => {
            const isFrozen = o.status === 'frozen';
            const needFirst = isFrozen && !o.first_approver;
            const needSecond = isFrozen && !!o.first_approver && !o.second_approver;
            const blockedBySod = needSecond && o.first_approver === myName;
            return (
              <tr key={o.order_id}>
                <td data-label={t.tx('订单 / 用户','Order / User')}>
                  <div className="text-mono" style={{ fontSize: 11 }}>{o.order_id}</div>
                  <div className="text-faint text-mono" style={{ fontSize: 10 }}>{o.user_id}</div>
                </td>
                <td data-label={t.tx('金额 / 手续费','Amount / Fee')} className="right tabular">
                  <div style={{ fontWeight: 500 }}>{fmtCN(o.amount)}</div>
                  <div className="text-faint" style={{ fontSize: 10 }}>{t.tx('手续费','Fee')} {fmtCN(o.fee)}</div>
                </td>
                <td data-label={t.tx('通道','Channel')}><span className="badge outline">{o.channel}</span></td>
                <td data-label={t.tx('状态','Status')}><StatusBadge status={o.status} t={t} /></td>
                <td data-label={t.tx('一审','1st Approver')} className="text-mono" style={{ fontSize: 11 }}>{o.first_approver || <span className="text-faint">—</span>}</td>
                <td data-label={t.tx('二审','2nd Approver')} className="text-mono" style={{ fontSize: 11 }}>{o.second_approver || <span className="text-faint">—</span>}</td>
                <td data-label={t.tx('创建时间','Created')} className="text-mono muted" style={{ fontSize: 11 }}>{_fmtTime(o.created_at)}</td>
                <td data-label={t.tx('操作', 'Actions')} className="tbl-actions">
                  {needFirst && (
                    <button className="btn btn-xs btn-pri" onClick={() => act(o.order_id, 'first-approve')}>{t.tx('一审通过','1st Approve')}</button>
                  )}
                  {needSecond && !blockedBySod && (
                    <button className="btn btn-xs btn-pri" onClick={() => act(o.order_id, 'second-approve')}>{t.tx('二审放款','2nd Approve')}</button>
                  )}
                  {needSecond && blockedBySod && (
                    <span className="text-faint" style={{ fontSize: 10 }}>{t.tx('需他人复核','Other admin required')}</span>
                  )}
                  {isFrozen && (
                    <button className="btn btn-xs btn-ghost" onClick={() => act(o.order_id, 'reject')}>{t.reject}</button>
                  )}
                  {!isFrozen && <span className="text-faint" style={{ fontSize: 10 }}>—</span>}
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// 13 AUDIT — 审计日志 / 链验证 / KYC 覆盖率 / 大额交易 / PII 访问
// ─────────────────────────────────────────────────────────────────────────────
function AuditScreen({ t, push }) {
  const [tab, setTab] = React.useState('log'); // log | chain | kyc | largetx | pii
  const tabs = [
    ['log',     t.tx('审计','Audit')],
    ['chain',   t.tx('链验证','Chain Verify')],
    ['kyc',     t.tx('KYC 覆盖率','KYC Coverage')],
    ['largetx', t.tx('大额交易','Large Tx')],
    ['pii',     t.tx('PII 访问','PII Access')],
  ];
  return (
    <div className="stack">
      <div className="page-h">
        <div>
          <h1>{t.tx('审计与合规','Audit & Compliance')}</h1>
          <div className="sub">{t.tx('特权操作留痕 · 哈希链不可篡改 · 合规报表','Privileged action trail · Tamper-evident hash chain · Compliance reports')}</div>
        </div>
      </div>
      <div className="card" style={{ padding: 8 }}>
        <div className="filter-bar" style={{ gap: 6 }}>
          {tabs.map(([k, l]) => (
            <span key={k} className={'chip' + (tab === k ? ' active' : '')} onClick={() => setTab(k)}>{l}</span>
          ))}
        </div>
      </div>
      {tab === 'log'     && <AuditLogTab t={t} push={push} />}
      {tab === 'chain'   && <AuditChainTab t={t} push={push} />}
      {tab === 'kyc'     && <AuditKYCCoverageTab t={t} push={push} />}
      {tab === 'largetx' && <AuditLargeTxTab t={t} push={push} />}
      {tab === 'pii'     && <AuditPIIAccessTab t={t} push={push} />}
    </div>
  );
}

// ── Tab 1: audit log (extended with hash + replay/diff side panel) ───────────
function AuditLogTab({ t, push }) {
  const [range, setRange] = React.useState('24h'); // 24h | 7d | 30d
  const [actionFilter, setActionFilter] = React.useState('');
  const [userFilter, setUserFilter] = React.useState('');
  const [selected, setSelected] = React.useState(null);
  const [detail, setDetail] = React.useState(null);

  const [audit] = _useAdminPoll('/api/audit?limit=200', 10000);
  const [events] = _useAdminPoll('/api/admin/events/recent?limit=200', 10000);

  const cutoff = React.useMemo(() => {
    const now = Date.now();
    const h = range === '24h' ? 24 : range === '7d' ? 24 * 7 : 24 * 30;
    return now - h * 3600 * 1000;
  }, [range]);

  const all = (audit && audit.entries) || [];
  const filtered = all.filter(e => {
    const ts = e.ts ? new Date(e.ts).getTime() : 0;
    if (ts && ts < cutoff) return false;
    if (actionFilter && !(e.action || '').toLowerCase().includes(actionFilter.toLowerCase())) return false;
    if (userFilter && !(e.userId || '').toLowerCase().includes(userFilter.toLowerCase())) return false;
    return true;
  });

  React.useEffect(() => {
    if (!selected && filtered.length > 0) setSelected(filtered[0]);
  }, [filtered, selected]);

  // Fetch the single-row detail (with hash_valid recomputation) whenever the
  // user selects a different row.
  React.useEffect(() => {
    if (!selected || !selected.id) { setDetail(null); return; }
    let cancelled = false;
    (async () => {
      try {
        const r = await _adminFetch(`/api/admin/audit/${selected.id}`);
        const j = await r.json();
        if (!cancelled) setDetail(j);
      } catch (e) {
        if (!cancelled) setDetail({ error: String(e && e.message || e) });
      }
    })();
    return () => { cancelled = true; };
  }, [selected && selected.id]);

  return (
    <div className="stack">
      <div className="card">
        <div className="filter-bar">
          {[['24h', t.tx('近 24h','Last 24h')], ['7d', t.tx('近 7 天','Last 7 days')], ['30d', t.tx('近 30 天','Last 30 days')]].map(([k, l]) => (
            <span key={k} className={'chip' + (range === k ? ' active' : '')} onClick={() => setRange(k)}>{l}</span>
          ))}
          <div style={{ flex: 1 }} />
          <input className="input" placeholder={t.tx('action 包含','action contains')} value={actionFilter} onChange={(e) => setActionFilter(e.target.value)} style={{ width: 200, height: 26, fontSize: 12 }} />
          <input className="input" placeholder="user_id" value={userFilter} onChange={(e) => setUserFilter(e.target.value)} style={{ width: 160, height: 26, fontSize: 12 }} />
          <span className="text-muted" style={{ fontSize: 11 }}>{t.tx('共','Total')} {all.length} · {t.tx('筛出','Filtered')} {filtered.length}</span>
        </div>
      </div>

      <div className="row-2 row-detail-split-audit">
        <div className="card">
          <div className="tbl-scroll">
          <table className="tbl tbl-stack">
            <thead><tr>
              <th>{t.tx('时间','Time')}</th>
              <th>{t.tx('角色','Role')}</th>
              <th>{t.tx('用户','User')}</th>
              <th>action</th>
              <th>target</th>
              <th>IP</th>
              <th>{t.tx('结果','Result')}</th>
            </tr></thead>
            <tbody>
              {filtered.length === 0 ? (
                <tr><td colSpan={7} className="muted" style={{ textAlign: 'center', padding: 24 }}>{t.tx('无审计记录','No audit records')}</td></tr>
              ) : filtered.map((e) => {
                const isSel = selected && selected.id === e.id;
                const ok = (e.result || '').startsWith('ok');
                return (
                  <tr key={e.id} onClick={() => setSelected(e)}
                      style={{ cursor: 'default', background: isSel ? 'var(--bg-active)' : undefined }}>
                    <td data-label={t.tx('时间','Time')} className="text-mono muted" style={{ fontSize: 11 }}>{_fmtTime(e.ts)}</td>
                    <td data-label={t.tx('角色','Role')}><span className="badge outline" style={{ fontSize: 10 }}>{e.role || '—'}</span></td>
                    <td data-label={t.tx('用户','User')} className="text-mono" style={{ fontSize: 11 }}>{e.userId || '—'}</td>
                    <td data-label="action" className="text-mono" style={{ fontSize: 11 }}>{e.action || '—'}</td>
                    <td data-label="target" className="text-mono muted" style={{ fontSize: 10, maxWidth: 220, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{e.target || '—'}</td>
                    <td data-label="IP" className="text-mono muted" style={{ fontSize: 11 }}>{e.ip || '—'}</td>
                    <td data-label={t.tx('结果','Result')}>
                      <span className={'badge ' + (ok ? 'success' : 'danger')} style={{ fontSize: 10 }}>{e.result || '—'}</span>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
          </div>
        </div>

        {/* Side panel: details + replay/diff (request_body) + related events */}
        <div className="card">
          <div className="card-h">
            <h3>{t.tx('详情 / 重放','Detail / Replay')}</h3>
            <span className="meta">{selected ? `#${selected.id}` : t.tx('未选中','Not selected')}</span>
          </div>
          <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 12 }}>
            {!selected ? (
              <div className="muted" style={{ fontSize: 12 }}>{t.tx('点击左侧条目查看详情','Click an entry on the left to view details')}</div>
            ) : <>
              <div>
                <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>action / target</div>
                <div className="text-mono" style={{ fontSize: 12 }}>{selected.action}</div>
                <div className="text-mono text-faint" style={{ fontSize: 11 }}>{selected.target || '—'}</div>
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, fontSize: 11 }}>
                <div><span className="text-muted">{t.tx('用户','User')}</span><br /><span className="text-mono">{selected.userId || '—'}</span></div>
                <div><span className="text-muted">{t.tx('角色','Role')}</span><br />{selected.role || '—'}</div>
                <div><span className="text-muted">IP</span><br /><span className="text-mono">{selected.ip || '—'}</span></div>
                <div><span className="text-muted">{t.tx('结果','Result')}</span><br />{selected.result || '—'}</div>
              </div>
              {detail && detail.entry && (
                <div>
                  <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>
                    {t.tx('哈希链','Hash chain')}{' '}
                    <span className={'badge ' + (detail.hash_valid ? 'success' : 'danger')} style={{ fontSize: 10 }}>
                      {detail.hash_valid ? t.tx('校验通过','Valid') : t.tx('已篡改','Tampered')}
                    </span>
                  </div>
                  <div className="text-mono text-faint" style={{ fontSize: 10, wordBreak: 'break-all' }}>
                    {t.tx('哈希','hash')}: {detail.entry.hash || '—'}<br />
                    {t.tx('前序','prev')}: {detail.entry.prev_hash || '—'}<br />
                    {t.tx('状态码','status')}: {detail.entry.response_status || '—'} · request_id: {detail.entry.request_id || '—'}
                  </div>
                </div>
              )}
              {detail && detail.entry && detail.entry.request_body ? (
                <div>
                  <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>{t.tx('请求体（用于重放/对比）','Request body (for replay / diff)')}</div>
                  <pre style={{
                    background: 'var(--bg-inset)', border: '1px solid var(--border)', borderRadius: 6,
                    padding: 10, fontSize: 11, fontFamily: 'var(--font-mono)', margin: 0,
                    maxHeight: 240, overflow: 'auto', whiteSpace: 'pre-wrap', wordBreak: 'break-all'
                  }}>{_prettyDetails(detail.entry.request_body)}</pre>
                </div>
              ) : null}
              <div>
                <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>details</div>
                <pre style={{
                  background: 'var(--bg-inset)', border: '1px solid var(--border)', borderRadius: 6,
                  padding: 10, fontSize: 11, fontFamily: 'var(--font-mono)', margin: 0,
                  maxHeight: 160, overflow: 'auto', whiteSpace: 'pre-wrap', wordBreak: 'break-all'
                }}>{_prettyDetails(selected.details)}</pre>
              </div>
              <div>
                <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>{t.tx('关联事件（同 user_id · ±5 分钟）','Related events (same user_id · ±5 min)')}</div>
                <RelatedEvents audit={selected} events={(events && events.events) || []} t={t} />
              </div>
            </>}
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Tab 2: chain verification ────────────────────────────────────────────────
function AuditChainTab({ t, push }) {
  const [busy, setBusy] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const [verifiedAt, setVerifiedAt] = React.useState(null);

  const run = async () => {
    if (busy) return;
    setBusy(true);
    try {
      const r = await _adminFetch('/api/admin/audit/verify-chain');
      const j = await r.json();
      setResult(j);
      setVerifiedAt(new Date());
      push(j.verified ? t.tx('哈希链校验通过','Hash chain verified') : t.tx('哈希链已损坏','Hash chain broken'));
    } catch (e) {
      setResult({ verified: false, reason: String(e && e.message || e) });
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="card" style={{ padding: 24 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 16 }}>
        <button className="btn btn-primary" disabled={busy} onClick={run}>
          {busy ? t.tx('校验中…','Verifying…') : t.tx('验证完整链','Verify full chain')}
        </button>
        {verifiedAt && (
          <span className="text-muted" style={{ fontSize: 12 }}>
            {t.tx('上次验证','Last verified')}: {verifiedAt.toLocaleString('zh-CN', { hour12: false })}
          </span>
        )}
      </div>
      {!result ? (
        <div className="muted" style={{ fontSize: 13 }}>
          {t.tx('点击按钮验证 audit_log 表的哈希链完整性。','Click the button to verify the integrity of the audit_log hash chain.')}
        </div>
      ) : result.verified ? (
        <div style={{
          padding: 16, borderRadius: 8,
          background: 'rgba(40, 167, 69, 0.12)', border: '1px solid rgba(40, 167, 69, 0.4)',
          color: '#1e7e34'
        }}>
          <div style={{ fontSize: 16, fontWeight: 600, marginBottom: 6 }}>
            ✓ {t.tx('哈希链完整','Hash chain intact')}
          </div>
          <div style={{ fontSize: 12 }}>
            {t.tx('已检查','Checked')} {result.checked || 0} {t.tx('行','rows')}
          </div>
        </div>
      ) : (
        <div style={{
          padding: 16, borderRadius: 8,
          background: 'rgba(220, 53, 69, 0.12)', border: '1px solid rgba(220, 53, 69, 0.4)',
          color: '#a71d2a'
        }}>
          <div style={{ fontSize: 16, fontWeight: 600, marginBottom: 6 }}>
            ✗ {t.tx('哈希链已损坏','Hash chain broken')}
          </div>
          <div className="text-mono" style={{ fontSize: 12 }}>
            broken_at_id: {result.broken_at_id || '—'} · {t.tx('原因','reason')}: {result.reason || '—'} · {t.tx('已检查','checked')}: {result.checked || 0}
          </div>
        </div>
      )}
    </div>
  );
}

// ── Tab 3: KYC coverage ──────────────────────────────────────────────────────
function AuditKYCCoverageTab({ t, push }) {
  const [data] = _useAdminPoll('/api/admin/compliance/kyc-coverage', 30000);
  if (!data) return <div className="card muted" style={{ padding: 24 }}>{t.tx('加载中…','Loading…')}</div>;
  const total = data.total_users || 0;
  const slices = [
    { key: 'approved', label: t.tx('已通过','Approved'),     val: data.kyc_approved   || 0, color: '#28a745' },
    { key: 'pending',  label: t.tx('审核中','Pending'),      val: data.kyc_pending    || 0, color: '#ffc107' },
    { key: 'rejected', label: t.tx('已拒绝','Rejected'),     val: data.kyc_rejected   || 0, color: '#dc3545' },
    { key: 'never',    label: t.tx('未提交','Never'),        val: data.never_submitted|| 0, color: '#6c757d' },
  ];
  // Build a simple SVG conic-gradient-style pie via stroke-dasharray on circles.
  const radius = 70;
  const c = 2 * Math.PI * radius;
  let offset = 0;
  return (
    <div className="stack">
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12 }}>
        {slices.map(s => (
          <div key={s.key} className="card" style={{ padding: 16 }}>
            <div className="text-muted" style={{ fontSize: 11 }}>{s.label}</div>
            <div style={{ fontSize: 24, fontWeight: 600, color: s.color }}>{s.val}</div>
            <div className="text-muted" style={{ fontSize: 10 }}>
              {total > 0 ? ((s.val / total) * 100).toFixed(1) : '0.0'}%
            </div>
          </div>
        ))}
      </div>
      <div className="card" style={{ padding: 24 }}>
        <h3 style={{ marginTop: 0 }}>{t.tx('KYC 状态分布','KYC status distribution')}</h3>
        <div style={{ display: 'flex', alignItems: 'center', gap: 32 }}>
          <svg width={180} height={180} viewBox="0 0 180 180">
            <circle cx={90} cy={90} r={radius} fill="none" stroke="var(--bg-inset)" strokeWidth={28} />
            {slices.map(s => {
              if (total === 0 || s.val === 0) return null;
              const frac = s.val / total;
              const dash = frac * c;
              const elem = (
                <circle key={s.key}
                  cx={90} cy={90} r={radius} fill="none" stroke={s.color} strokeWidth={28}
                  strokeDasharray={`${dash} ${c - dash}`}
                  strokeDashoffset={-offset}
                  transform="rotate(-90 90 90)" />
              );
              offset += dash;
              return elem;
            })}
            <text x={90} y={90} textAnchor="middle" dominantBaseline="central"
                  style={{ fontSize: 16, fontWeight: 600, fill: 'var(--text)' }}>
              {(data.coverage_pct || 0).toFixed(1)}%
            </text>
            <text x={90} y={108} textAnchor="middle"
                  style={{ fontSize: 10, fill: 'var(--text-muted)' }}>
              {t.tx('覆盖率','Coverage')}
            </text>
          </svg>
          <div style={{ flex: 1 }}>
            <div className="tbl-scroll">
            <table className="tbl tbl-stack">
              <tbody>
                {slices.map(s => (
                  <tr key={s.key}>
                    <td data-label={t.tx('状态','Status')}><span style={{ display: 'inline-block', width: 12, height: 12, background: s.color, borderRadius: 2, marginRight: 8, verticalAlign: 'middle' }} />{s.label}</td>
                    <td data-label={t.tx('人数','Count')} className="text-mono" style={{ textAlign: 'right' }}>{s.val}</td>
                    <td data-label={t.tx('占比','Share')} className="text-mono text-muted" style={{ textAlign: 'right' }}>
                      {total > 0 ? ((s.val / total) * 100).toFixed(1) : '0.0'}%
                    </td>
                  </tr>
                ))}
                <tr style={{ borderTop: '1px solid var(--border)' }}>
                  <td data-label={t.tx('总用户','Total users')}>{t.tx('总用户','Total users')}</td>
                  <td data-label={t.tx('人数','Count')} className="text-mono" style={{ textAlign: 'right', fontWeight: 600 }}>{total}</td>
                  <td />
                </tr>
              </tbody>
            </table>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Tab 4: large transactions ────────────────────────────────────────────────
function AuditLargeTxTab({ t, push }) {
  const [days, setDays]   = React.useState(30);
  const [min, setMin]     = React.useState(10000);
  const url = `/api/admin/compliance/large-tx?days=${days}&min=${min}`;
  const [data] = _useAdminPoll(url, 30000);
  const items = (data && data.items) || [];
  const exportCSV = () => {
    // Use a plain link so the browser handles the download with auth cookies.
    const a = document.createElement('a');
    a.href = url + '&format=csv';
    a.target = '_blank';
    a.rel = 'noopener';
    a.click();
    push(t.tx('开始下载 CSV','Started CSV download'));
  };
  return (
    <div className="stack">
      <div className="card">
        <div className="filter-bar">
          <span className="text-muted" style={{ fontSize: 11 }}>{t.tx('窗口','Window')}</span>
          {[7, 30, 90].map(d => (
            <span key={d} className={'chip' + (days === d ? ' active' : '')} onClick={() => setDays(d)}>{d}d</span>
          ))}
          <span className="text-muted" style={{ fontSize: 11, marginLeft: 16 }}>{t.tx('门槛','Min')}</span>
          <input className="input" type="number" value={min} onChange={(e) => setMin(Number(e.target.value) || 0)}
                 style={{ width: 120, height: 26, fontSize: 12 }} />
          <div style={{ flex: 1 }} />
          <span className="text-muted" style={{ fontSize: 11 }}>{t.tx('命中','Hits')}: {items.length}</span>
          <button className="btn btn-sm" onClick={exportCSV}><Icons.download /> {t.tx('导出 CSV','Export CSV')}</button>
        </div>
      </div>
      <div className="card">
        <div className="tbl-scroll">
        <table className="tbl tbl-stack">
          <thead><tr>
            <th>{t.tx('时间','Time')}</th>
            <th>{t.tx('类型','Kind')}</th>
            <th>ID</th>
            <th>{t.tx('用户','User')}</th>
            <th>KYC</th>
            <th style={{ textAlign: 'right' }}>{t.tx('金额','Amount')}</th>
          </tr></thead>
          <tbody>
            {items.length === 0 ? (
              <tr><td colSpan={6} className="muted" style={{ textAlign: 'center', padding: 24 }}>{t.tx('无命中记录','No matching transactions')}</td></tr>
            ) : items.map((x, i) => {
              const kycCls = x.kyc_status === 'approved' ? 'success' :
                             x.kyc_status === 'rejected' ? 'danger' :
                             x.kyc_status === 'pending'  ? 'warning' : 'outline';
              return (
                <tr key={x.kind + ':' + x.id + ':' + i}>
                  <td data-label={t.tx('时间','Time')} className="text-mono muted" style={{ fontSize: 11 }}>{_fmtTime(x.ts)}</td>
                  <td data-label={t.tx('类型','Kind')}><span className="badge outline" style={{ fontSize: 10 }}>{x.kind}</span></td>
                  <td data-label="ID" className="text-mono" style={{ fontSize: 10 }}>{x.id}</td>
                  <td data-label={t.tx('用户','User')}>
                    <div className="text-mono" style={{ fontSize: 11 }}>{x.user_id}</div>
                    <div className="text-faint" style={{ fontSize: 10 }}>{x.user_name || '—'}</div>
                  </td>
                  <td data-label="KYC"><span className={'badge ' + kycCls} style={{ fontSize: 10 }}>{x.kyc_status}</span></td>
                  <td data-label={t.tx('金额','Amount')} className="text-mono" style={{ textAlign: 'right', fontVariantNumeric: 'tabular-nums' }}>
                    ¥{(x.amount || 0).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
        </div>
      </div>
    </div>
  );
}

// ── Tab 5: PII access ────────────────────────────────────────────────────────
function AuditPIIAccessTab({ t, push }) {
  const [days, setDays] = React.useState(7);
  const [data] = _useAdminPoll(`/api/admin/compliance/pii-access?days=${days}`, 30000);
  const entries = (data && data.entries) || [];
  const sorted = entries.slice().sort((a, b) => (b.count || 0) - (a.count || 0));
  return (
    <div className="stack">
      <div className="card">
        <div className="filter-bar">
          <span className="text-muted" style={{ fontSize: 11 }}>{t.tx('窗口','Window')}</span>
          {[1, 7, 30].map(d => (
            <span key={d} className={'chip' + (days === d ? ' active' : '')} onClick={() => setDays(d)}>{d}d</span>
          ))}
          <div style={{ flex: 1 }} />
          <span className="text-muted" style={{ fontSize: 11 }}>{t.tx('涉及','Actors')}: {sorted.length}</span>
        </div>
      </div>
      <div className="card">
        <div className="tbl-scroll">
        <table className="tbl tbl-stack">
          <thead><tr>
            <th>{t.tx('账号','Actor')}</th>
            <th>{t.tx('姓名','Name')}</th>
            <th style={{ textAlign: 'right' }}>{t.tx('访问次数','Accesses')}</th>
            <th>{t.tx('最近访问','Last access')}</th>
            <th>{t.tx('最近目标','Last target')}</th>
          </tr></thead>
          <tbody>
            {sorted.length === 0 ? (
              <tr><td colSpan={5} className="muted" style={{ textAlign: 'center', padding: 24 }}>{t.tx('窗口内无 PII 访问','No PII access in window')}</td></tr>
            ) : sorted.map((e, i) => (
              <tr key={(e.actor || '') + ':' + i}>
                <td data-label={t.tx('账号','Actor')} className="text-mono" style={{ fontSize: 11 }}>{e.actor}</td>
                <td data-label={t.tx('姓名','Name')}>{e.actor_name || '—'}</td>
                <td data-label={t.tx('访问次数','Accesses')} className="text-mono" style={{ textAlign: 'right' }}>{e.count}</td>
                <td data-label={t.tx('最近访问','Last access')} className="text-mono muted" style={{ fontSize: 11 }}>{_fmtTime(e.last_access)}</td>
                <td data-label={t.tx('最近目标','Last target')} className="text-mono muted" style={{ fontSize: 10, maxWidth: 320, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{e.last_target || '—'}</td>
              </tr>
            ))}
          </tbody>
        </table>
        </div>
      </div>
    </div>
  );
}

function _prettyDetails(d) {
  if (!d) return '—';
  if (typeof d === 'string') {
    try { return JSON.stringify(JSON.parse(d), null, 2); } catch (e) { return d; }
  }
  try { return JSON.stringify(d, null, 2); } catch (e) { return String(d); }
}

function RelatedEvents({ audit, events, t }) {
  const uid = audit.userId;
  const ts = audit.ts ? new Date(audit.ts).getTime() : 0;
  const related = (events || []).filter(ev => {
    if (uid && ev.user_id !== uid && ev.userId !== uid) return false;
    if (ts && ev.ts) {
      const evt = new Date(ev.ts).getTime();
      if (Math.abs(evt - ts) > 5 * 60 * 1000) return false;
    }
    return true;
  }).slice(0, 6);

  const _tx = (t && t.tx) ? t.tx : ((zh) => zh);
  if (related.length === 0) return <div className="muted" style={{ fontSize: 12 }}>{_tx('无关联事件','No related events')}</div>;
  return (
    <div className="tbl-scroll">
    <table className="tbl tbl-stack" style={{ marginTop: 0 }}>
      <tbody>
        {related.map((ev, i) => (
          <tr key={ev.id || i}>
            <td data-label={_tx('时间','Time')} className="text-mono muted" style={{ fontSize: 10 }}>{_fmtTimeShort(ev.ts)}</td>
            <td data-label={_tx('类型','Kind')} className="text-mono" style={{ fontSize: 11 }}>{ev.kind || ev.type || '—'}</td>
            <td data-label={_tx('引用','Ref')} className="text-faint" style={{ fontSize: 10 }}>{ev.ref || ev.target || ''}</td>
          </tr>
        ))}
      </tbody>
    </table>
    </div>
  );
}

// Local Field — small wrapper used by WalletAdjustModal so this file is self-contained.
function _Field({ label, children }) {
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      <span className="text-muted" style={{ fontSize: 11 }}>{label}</span>
      {children}
    </label>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// 10 MARKETING — unchanged (layered activity editor mock; kept for routing)
// ─────────────────────────────────────────────────────────────────────────────
function MarketingLiveActivities({ t, push }) {
  const [data, err] = _useAdminPoll('/api/admin/marketing/stats', 15000);
  const [busy, setBusy] = React.useState('');
  const acts = (data && data.activities) || [];

  const toggle = async (code) => {
    if (busy) return;
    setBusy(code);
    try {
      const r = await _adminFetch(`/api/admin/marketing/${code}/toggle`, { method: 'POST' });
      const j = await r.json().catch(() => ({}));
      push(t.tx('活动状态已切换', 'Activity toggled') + ': ' + code + ' → ' + (j.active ? 'on' : 'off'));
    } catch (e) {
      push(t.tx('切换失败', 'Toggle failed') + ': ' + (e && e.message || 'unknown'));
    } finally {
      setBusy('');
    }
  };

  return (
    <div className="card">
      <div className="card-h"><h3>{t.tx('运营活动（实时）', 'Live Activities')}</h3>
        <span className="text-faint" style={{ fontSize: 11 }}>{t.tx('24h 参与数与派发金额', 'Last 24h participants & payout')}</span>
      </div>
      {err && <div style={{ padding: 12, color: 'var(--danger)' }}>{t.tx('加载失败', 'Load failed')}: {String(err)}</div>}
      <div className="tbl-scroll">
      <table className="tbl tbl-stack">
        <thead><tr>
          <th>{t.tx('活动', 'Activity')}</th>
          <th>{t.tx('代码', 'Code')}</th>
          <th className="right">{t.tx('24h 参与', '24h Participants')}</th>
          <th className="right">{t.tx('24h 派发', '24h Payout')}</th>
          <th>{t.tx('状态', 'Status')}</th>
          <th></th>
        </tr></thead>
        <tbody>
          {acts.map((a) => (
            <tr key={a.code}>
              <td data-label={t.tx('活动', 'Activity')} style={{ fontWeight: 500 }}>{a.name}</td>
              <td data-label={t.tx('代码', 'Code')} className="text-mono text-faint" style={{ fontSize: 11 }}>{a.code}</td>
              <td data-label={t.tx('24h 参与', '24h Participants')} className="right tabular">{fmtNum(a.participants_24h)}</td>
              <td data-label={t.tx('24h 派发', '24h Payout')} className="right tabular">¥{Number(a.payout_24h || 0).toFixed(2)}</td>
              <td data-label={t.tx('状态', 'Status')}>
                <span style={{
                  padding: '2px 8px', borderRadius: 100, fontSize: 10, fontWeight: 600,
                  background: a.active ? 'var(--success-soft)' : 'var(--bg-inset)',
                  color: a.active ? 'var(--success)' : 'var(--text-faint)',
                }}>
                  {a.active ? t.tx('运行中', 'Active') : t.tx('已暂停', 'Paused')}
                </span>
              </td>
              <td data-label={t.tx('操作', 'Actions')} className="tbl-actions">
                <button className="btn btn-xs" onClick={() => toggle(a.code)} disabled={busy === a.code}>
                  {a.active ? t.tx('临时关停', 'Pause') : t.tx('恢复', 'Resume')}
                </button>
                <button className="btn btn-xs btn-ghost" onClick={() => push(t.tx('明细暂未实现', 'Details TBD'))}>
                  {t.tx('查看明细', 'Details')}
                </button>
              </td>
            </tr>
          ))}
          {acts.length === 0 && !err && (
            <tr><td colSpan={6} style={{ textAlign: 'center', padding: 20, color: 'var(--text-faint)' }}>{t.tx('加载中…', 'Loading…')}</td></tr>
          )}
        </tbody>
      </table>
      </div>
    </div>
  );
}

function MarketingScreen({ t, push }) {
  const [selectedAct, setSelectedAct] = React.useState(null);
  return (
    <div className="stack">
      <div className="page-h">
        <div>
          <h1>{t.p_marketing}</h1>
          <div className="sub">{t.tx('6 个活动 · 12 个分层版本 · ROI 3.4× · 预算 ¥3.16M','6 campaigns · 12 tiered versions · ROI 3.4× · Budget ¥3.16M')}</div>
        </div>
        <div className="actions">
          <button className="btn btn-sm"><Icons.copy /> {t.tx('模板库','Templates')}</button>
          <button className="btn btn-pri btn-sm" onClick={() => push(t.tx('新建活动向导已打开','New campaign wizard opened'))}><Icons.plus /> {t.tx('新建活动','New Campaign')}</button>
        </div>
      </div>

      <MarketingLiveActivities t={t} push={push} />

      <div className="row-4">
        <KPI label={t.tx('进行中','Active')} value="4" delta={t.tx('本月 +2','+2 this month')} up spark={<MiniBars data={[2,3,3,4,4]} w={80} h={22} />} />
        <KPI label={t.tx('参与人次','Participants')} value="64,448" delta="+18.4%" up spark={<Sparkline data={[40,42,48,52,58,62,66]} w={80} h={22} stroke="oklch(0.6 0.16 145)" />} />
        <KPI label={t.tx('奖励派发','Rewards Paid')} value="¥811k" delta="+12.1%" up spark={<Sparkline data={[40,48,52,58,62,68,72]} w={80} h={22} stroke="oklch(0.65 0.14 30)" />} />
        <KPI label={t.tx('平均 ROI','Avg ROI')} value="3.4×" delta="+0.6×" up spark={<Sparkline data={[2.4,2.6,2.8,3.0,3.2,3.3,3.4]} w={80} h={22} />} />
      </div>

      <div className="card">
        <div className="filter-bar">
          <span className="chip active">{t.tx('全部','All')} 6</span>
          <span className="chip">{t.tx('进行中','Active')} 4</span>
          <span className="chip">{t.tx('草稿','Draft')} 1</span>
          <span className="chip">{t.tx('已结束','Ended')} 5</span>
          <div style={{ flex: 1 }} />
          <button className="btn btn-sm btn-ghost"><Icons.filter /> {t.tx('更多筛选','More Filters')}</button>
        </div>
        <div className="tbl-scroll">
        <table className="tbl tbl-stack">
          <thead><tr>
            <th>{t.tx('活动','Campaign')}</th><th>{t.tx('类型','Type')}</th><th>{t.tx('分层版本','Tiered Version')}</th><th>{t.tx('周期','Period')}</th><th className="right">{t.tx('预算 / 使用','Budget / Used')}</th>
            <th className="right">{t.tx('参与','Joined')}</th><th>ROI</th><th>{t.tx('状态','Status')}</th><th></th>
          </tr></thead>
          <tbody>
            {DATA.activities.map((a) => (
              <tr key={a.id} onClick={() => setSelectedAct(a)} style={{ cursor: 'default' }}>
                <td data-label={t.tx('活动','Campaign')}>
                  <div style={{ fontWeight: 500 }}>{a.name}</div>
                  <div className="text-mono text-faint" style={{ fontSize: 10 }}>{a.id}</div>
                </td>
                <td data-label={t.tx('类型','Type')} className="muted">{a.type}</td>
                <td data-label={t.tx('分层版本','Tiered Version')}>
                  {a.layers > 1 ? (
                    <button className="btn btn-xs" onClick={(e) => { e.stopPropagation(); setSelectedAct(a); }}>
                      <Icons.level /> {a.layers} {t.tx('个等级版本','tier versions')}
                    </button>
                  ) : <span className="text-faint">{t.tx('单一版本','Single version')}</span>}
                </td>
                <td data-label={t.tx('周期','Period')} className="text-mono muted" style={{ fontSize: 11 }}>{a.start} → {a.end}</td>
                <td data-label={t.tx('预算 / 使用','Budget / Used')} className="right tabular">
                  <div>¥{a.budget.toLocaleString()}</div>
                  <div className="text-faint" style={{ fontSize: 10 }}>{t.tx('已用','Used')} {Math.round((a.used / a.budget) * 100)}%</div>
                </td>
                <td data-label={t.tx('参与','Joined')} className="right tabular">{fmtNum(a.claims)}</td>
                <td data-label="ROI" className="tabular">{a.roi ? a.roi + '×' : '—'}</td>
                <td data-label={t.tx('状态','Status')}><StatusBadge status={a.status} t={t} /></td>
                <td data-label={t.tx('操作', 'Actions')} className="tbl-actions">
                  <button className="btn btn-xs" onClick={(e) => { e.stopPropagation(); setSelectedAct(a); }}>{t.edit}</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
        </div>
      </div>

      {selectedAct && <LayeredActivityModal activity={selectedAct} onClose={() => setSelectedAct(null)} t={t} push={push} />}
    </div>
  );
}

function LayeredActivityModal({ activity, onClose, t, push }) {
  const [tier, setTier] = React.useState('gold');
  const layers = {
    normal:  { title: t.tx('充值返利活动','Deposit Rebate'), sub: t.tx('充得越多，返得越多','The more you deposit, the more you get back'), banner: 'oklch(0.85 0.05 50)',  amount: t.tx('充值 100 送 20','Deposit 100 get 20'), bonus: '20%', cap: 200,    btn: t.tx('立即充值','Deposit Now'),     reward: 480,  cond: t.tx('无限制','No limit') },
    gold:    { title: t.tx('黄金会员专属返利','Gold Member Exclusive Rebate'), sub: t.tx('黄金会员每日额外 +30%','Gold members get extra +30% daily'), banner: 'oklch(0.78 0.13 85)', amount: t.tx('充值 1,000 送 120','Deposit 1,000 get 120'), bonus: '12%', cap: 1500,   btn: t.tx('领取黄金奖励','Claim Gold Reward'), reward: 1200, cond: t.tx('黄金会员 · 当日首充','Gold member · First deposit of the day') },
    diamond: { title: t.tx('钻石 VIP 专属礼遇','Diamond VIP Exclusive'), sub: t.tx('钻石会员专属客户经理派送','Sent by dedicated account manager'), banner: 'oklch(0.7 0.15 230)', amount: t.tx('充值 10,000 送 1,500','Deposit 10,000 get 1,500'), bonus: '15%', cap: 50000, btn: t.tx('联系专属客服','Contact VIP Support'), reward: 1500, cond: t.tx('钻石会员 · 单笔 ≥ ¥1万','Diamond member · Single ≥ ¥10k') },
    supreme: { title: t.tx('至尊会员私享礼遇','Supreme Member Private Gift'), sub: t.tx('由 CEO 团队个性化定制','Personalized by the CEO team'), banner: 'oklch(0.6 0.18 305)', amount: t.tx('充值 100,000 送 25,000','Deposit 100,000 get 25,000'), bonus: '25%', cap: 200000, btn: t.tx('私享礼遇','Private Gift'), reward: 25000, cond: t.tx('至尊会员 · 单笔 ≥ ¥10万','Supreme member · Single ≥ ¥100k') },
  };
  const tiers = [
    { id: 'normal',  name: t.tx('普通','Normal'),   key: 'normal' },
    { id: 'gold',    name: t.tx('黄金','Gold'),     key: 'gold' },
    { id: 'diamond', name: t.tx('钻石','Diamond'),  key: 'diamond' },
    { id: 'supreme', name: t.tx('至尊','Supreme'),  key: 'supreme' },
  ];
  const cur = layers[tier];

  return (
    <Modal open={true} onClose={onClose} title={`${activity.name} · ${t.tx('分层版本编辑器','Tiered Version Editor')}`} width={920}
           footer={<>
             <span className="text-muted" style={{ fontSize: 11.5, marginRight: 'auto' }}>
               <Icons.shield /> {t.tx('任何编辑都需要审批后上线','All edits require approval before going live')}
             </span>
             <button className="btn btn-sm" onClick={onClose}>{t.cancel}</button>
             <button className="btn btn-sm">{t.tx('保存草稿','Save Draft')}</button>
             <button className="btn btn-pri btn-sm" onClick={() => { onClose(); push(`${activity.name} · ${tier} ${t.tx('版本已提交审批','version submitted for approval')}`); }}>{t.tx('提交审批','Submit for Approval')}</button>
           </>}>
      <div style={{ display: 'grid', gridTemplateColumns: '160px 1fr 280px', gap: 16 }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
          <div className="text-muted" style={{ fontSize: 11, padding: '4px 0' }}>{t.tx('分层版本','Tiered Versions')}</div>
          {tiers.map((tr) => (
            <div key={tr.id} onClick={() => setTier(tr.key)}
                 style={{
                   padding: '10px 12px',
                   borderRadius: 8,
                   border: '1px solid ' + (tier === tr.key ? 'var(--accent)' : 'var(--border)'),
                   background: tier === tr.key ? 'var(--accent-soft)' : 'var(--bg-card)',
                   cursor: 'default'
                 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                <TierBadge tier={tr.key} t={t} />
                <span style={{ fontSize: 12, fontWeight: 500 }}>{tr.name}</span>
              </div>
              <div className="text-faint" style={{ fontSize: 10, marginTop: 3, fontFamily: 'var(--font-mono)' }}>
                {layers[tr.key].bonus} · {t.tx('上限','Cap')} ¥{layers[tr.key].cap}
              </div>
            </div>
          ))}
          <button className="btn btn-xs btn-ghost" style={{ justifyContent: 'flex-start', marginTop: 4 }}>
            <Icons.plus /> {t.tx('添加版本','Add Version')}
          </button>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div className="card-h" style={{ padding: 0, paddingBottom: 8, borderBottom: '1px dashed var(--border)' }}>
            <h3>{tiers.find(x => x.key === tier).name} {t.tx('版本配置','Version Config')}</h3>
            <button className="btn btn-xs btn-ghost"><Icons.copy /> {t.tx('复制自其它版本','Copy from another version')}</button>
          </div>
          <_Field label={t.tx('活动标题','Campaign Title')}><input className="input" value={cur.title} readOnly /></_Field>
          <_Field label={t.tx('副标题 / 弹窗文案','Subtitle / Popup Copy')}><input className="input" value={cur.sub} readOnly /></_Field>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <_Field label={t.tx('奖励比例','Reward Ratio')}><input className="input" value={cur.bonus} readOnly /></_Field>
            <_Field label={t.tx('单笔上限','Per-Transaction Cap')}><input className="input" value={'¥ ' + cur.cap} readOnly /></_Field>
          </div>
          <_Field label={t.tx('按钮文案','Button Copy')}><input className="input" value={cur.btn} readOnly /></_Field>
          <_Field label={t.tx('参与条件','Eligibility')}>
            <textarea className="textarea" rows={2} value={cur.cond} readOnly />
          </_Field>
        </div>

        <div>
          <div className="text-muted" style={{ fontSize: 11, marginBottom: 8 }}>{t.tx('用户端预览','User Preview')}</div>
          <div style={{ background: 'var(--bg-inset)', borderRadius: 12, padding: 14, border: '1px solid var(--border)' }}>
            <div style={{ background: cur.banner, height: 96, borderRadius: 10, padding: 12, display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', color: 'oklch(0.2 0.05 50)', position: 'relative', overflow: 'hidden' }}>
              <div style={{ position: 'absolute', top: 10, right: 12, background: 'rgba(0,0,0,.18)', color: 'white', padding: '2px 8px', borderRadius: 4, fontSize: 10, fontWeight: 600, letterSpacing: '.02em' }}>
                <TierBadge tier={tier} t={t} />
              </div>
              <div style={{ fontSize: 15, fontWeight: 700, marginBottom: 2 }}>{cur.title}</div>
              <div style={{ fontSize: 11, opacity: 0.85 }}>{cur.sub}</div>
            </div>
            <div style={{ background: 'var(--bg-card)', borderRadius: 8, padding: 14, marginTop: 10, border: '1px solid var(--border)' }}>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginBottom: 4 }}>{t.tx('本次最高可得','Max reward this time')}</div>
              <div style={{ fontSize: 22, fontWeight: 700, color: cur.banner, marginBottom: 2 }}>+ ¥{cur.reward.toLocaleString()}</div>
              <div style={{ fontSize: 11, color: 'var(--text-muted)', marginBottom: 12 }}>{cur.amount}</div>
              <button style={{
                width: '100%', padding: '10px 16px', borderRadius: 8,
                background: 'var(--text)', color: 'white', border: 0, fontSize: 13, fontWeight: 600, cursor: 'default'
              }}>{cur.btn}</button>
              <div style={{ fontSize: 10, color: 'var(--text-faint)', marginTop: 8, textAlign: 'center' }}>{cur.cond}</div>
            </div>
          </div>
        </div>
      </div>
    </Modal>
  );
}

Object.assign(window, { FinanceScreen, PaymentsScreen, AuditScreen, MarketingScreen });
