// screens-announce.jsx — 公告管理（草稿/发布/暂停/统计）

const { adminFetch: _annFetch, useAdminPoll: _annPoll } = window.NebulaAdmin;

// ─── helpers ────────────────────────────────────────────────────────────────
function _annFmtTime(iso) {
  if (!iso) return '—';
  try { return new Date(iso).toLocaleString('zh-CN', { hour12: false }); } catch (e) { return iso; }
}
function _annFmtDtLocal(iso) {
  // datetime-local 输入需要 YYYY-MM-DDTHH:mm
  if (!iso) return '';
  const d = new Date(iso);
  if (isNaN(d.getTime())) return '';
  const pad = (n) => String(n).padStart(2, '0');
  return d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate())
       + 'T' + pad(d.getHours()) + ':' + pad(d.getMinutes());
}
function _annTrunc(s, n) {
  s = s || '';
  return s.length > n ? s.slice(0, n) + '…' : s;
}
function _annStatusColor(s) {
  if (s === 'draft') return 'outline';
  if (s === 'scheduled') return 'info';
  if (s === 'live') return 'success';
  if (s === 'paused') return 'warning';
  if (s === 'ended') return 'outline';
  return 'outline';
}
function _annPlacementColor(p) {
  if (p === 'popup') return 'purple';
  if (p === 'banner') return 'accent';
  if (p === 'floating') return 'info';
  if (p === 'system_top') return 'warning';
  return 'outline';
}

// ─── Field ──────────────────────────────────────────────────────────────────
function _AnnField({ label, hint, children }) {
  return (
    <div className="field" style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      <label style={{ fontSize: 11, color: 'var(--text-muted)' }}>{label}</label>
      {children}
      {hint && <div className="text-faint" style={{ fontSize: 10 }}>{hint}</div>}
    </div>
  );
}

// ─── KPI strip cell ─────────────────────────────────────────────────────────
function _AnnStatCell({ label, value, color }) {
  return (
    <div>
      <div className="text-muted" style={{ fontSize: 11, marginBottom: 2 }}>{label}</div>
      <div className="tabular" style={{ fontSize: 18, fontWeight: 700, color: color || 'var(--text)' }}>{value}</div>
    </div>
  );
}

// ─── AnnouncementsScreen ────────────────────────────────────────────────────
function AnnouncementsScreen({ t, push }) {
  push = push || ((m) => console.log('[announce]', m));
  const [statusFilter, setStatusFilter] = React.useState('');
  const [placementFilter, setPlacementFilter] = React.useState('');
  const [freqFilter, setFreqFilter] = React.useState('');
  const [expandedId, setExpandedId] = React.useState(null);
  const [tick, setTick] = React.useState(0);
  const bump = () => setTick(v => v + 1);

  const [showNew, setShowNew] = React.useState(false);
  const [editing, setEditing] = React.useState(null); // 公告对象
  const [statsFor, setStatsFor] = React.useState(null); // 公告对象

  const listPath = React.useMemo(() => {
    const p = new URLSearchParams();
    if (statusFilter) p.set('status', statusFilter);
    p.set('_', String(tick));
    return '/api/admin/announcements?' + p.toString();
  }, [statusFilter, tick]);

  const [listData, listErr] = _annPoll(listPath, 10000);
  const allItems = (listData && (listData.announcements || listData.items || listData.list)) || [];

  // 前端做 placement / freq filter (后端只接 status)
  const items = React.useMemo(() => {
    return allItems.filter(a => {
      if (placementFilter && a.placement !== placementFilter) return false;
      if (freqFilter && a.frequency !== freqFilter) return false;
      return true;
    });
  }, [allItems, placementFilter, freqFilter]);

  // KPI 聚合
  const kpi = React.useMemo(() => {
    const r = { draft: 0, live: 0, paused: 0, ended: 0, scheduled: 0, popupLive: 0 };
    let topPopupPri = -1;
    for (const a of allItems) {
      if (a.status in r) r[a.status]++;
      if (a.status === 'live' && a.placement === 'popup') {
        r.popupLive++;
        if ((a.priority || 0) > topPopupPri) topPopupPri = a.priority || 0;
      }
    }
    r.topPopupPri = topPopupPri < 0 ? '—' : topPopupPri;
    return r;
  }, [allItems]);

  const refresh = () => setTimeout(bump, 1000);

  const doPublish = async (a) => {
    if (!confirm(t.tx(`发布公告「${a.title || a.code}」？`, `Publish announcement "${a.title || a.code}"?`))) return;
    try {
      await _annFetch(`/api/admin/announcements/${a.id}/publish`, { method: 'POST', body: JSON.stringify({}) });
      push(t.tx('已发布', 'Published'));
      refresh();
    } catch (e) { push(t.tx('发布失败: ', 'Publish failed: ') + (e.body?.error || e.message || e)); }
  };
  const doPause = async (a) => {
    if (!confirm(t.tx(`暂停公告「${a.title || a.code}」？`, `Pause announcement "${a.title || a.code}"?`))) return;
    try {
      await _annFetch(`/api/admin/announcements/${a.id}/pause`, { method: 'POST', body: JSON.stringify({}) });
      push(t.tx('已暂停', 'Paused'));
      refresh();
    } catch (e) { push(t.tx('暂停失败: ', 'Pause failed: ') + (e.body?.error || e.message || e)); }
  };
  const doDelete = async (a) => {
    if (!confirm(t.tx(`删除（软删 → ended）公告「${a.title || a.code}」？`, `Delete (soft → ended) announcement "${a.title || a.code}"?`))) return;
    try {
      await _annFetch(`/api/admin/announcements/${a.id}`, { method: 'DELETE' });
      push(t.tx('已删除', 'Deleted'));
      refresh();
    } catch (e) { push(t.tx('删除失败: ', 'Delete failed: ') + (e.body?.error || e.message || e)); }
  };

  return (
    <div className="stack">
      <div className="page-h">
        <div>
          <h1>{t.tx('公告管理', 'Announcements')}</h1>
          <div className="sub">{t.tx('popup / banner / floating / system_top · 草稿→发布→暂停→结束', 'popup / banner / floating / system_top · draft → publish → pause → end')}</div>
        </div>
        <div className="actions">
          <button className="btn btn-sm" onClick={bump}>{t.tx('刷新', 'Refresh')}</button>
          <button className="btn btn-pri btn-sm" onClick={() => setShowNew(true)}>{t.tx('+ 新建公告', '+ New Announcement')}</button>
        </div>
      </div>

      {/* KPI strip */}
      <div className="card" style={{ padding: 14 }}>
        <div style={{ display: 'flex', gap: 18, flexWrap: 'wrap', alignItems: 'center' }}>
          <_AnnStatCell label={t.tx('草稿', 'Draft')} value={kpi.draft} />
          <div className="divider-v" style={{ height: 30 }} />
          <_AnnStatCell label={t.tx('已排期', 'Scheduled')} value={kpi.scheduled} />
          <div className="divider-v" style={{ height: 30 }} />
          <_AnnStatCell label={t.tx('进行中 (live)', 'Live')} value={kpi.live} color="var(--success)" />
          <div className="divider-v" style={{ height: 30 }} />
          <_AnnStatCell label={t.tx('暂停', 'Paused')} value={kpi.paused} color="var(--warning)" />
          <div className="divider-v" style={{ height: 30 }} />
          <_AnnStatCell label={t.tx('已结束', 'Ended')} value={kpi.ended} />
          <div className="divider-v" style={{ height: 30 }} />
          <_AnnStatCell label={t.tx('当前 popup live', 'Current popup live')} value={kpi.popupLive + (t.tx(' (最高 P', ' (max P')) + kpi.topPopupPri + ')'} color="var(--accent-text)" />
        </div>
      </div>

      {listErr && (
        <div className="card" style={{ padding: 16, color: 'var(--danger)', fontSize: 12 }}>
          {t.tx('加载失败: ', 'Load failed: ')}{String(listErr.message || listErr)}
        </div>
      )}

      <div style={{ display: 'grid', gridTemplateColumns: expandedId ? '6fr 4fr' : '1fr', gap: 14 }}>
        {/* 左 60%：列表 */}
        <div className="card" style={{ display: 'flex', flexDirection: 'column' }}>
          <div className="card-h">
            <h3>{t.tx('公告列表', 'Announcements')}</h3>
            <span className="meta">{items.length} / {allItems.length}{t.tx(' 条', ' items')}</span>
          </div>
          {/* filter chip rows */}
          <div style={{ padding: '10px 12px', borderBottom: '1px solid var(--border)', display: 'flex', flexDirection: 'column', gap: 6 }}>
            <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap', alignItems: 'center' }}>
              <span className="text-faint" style={{ fontSize: 10, width: 50 }}>{t.tx('状态', 'Status')}</span>
              {['', 'draft', 'scheduled', 'live', 'paused', 'ended'].map(s => (
                <button key={'s' + s}
                        className={'chip ' + (statusFilter === s ? 'active' : '')}
                        style={{ fontSize: 10 }}
                        onClick={() => setStatusFilter(s)}>
                  {s === '' ? t.tx('全部', 'All') : s}
                </button>
              ))}
            </div>
            <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap', alignItems: 'center' }}>
              <span className="text-faint" style={{ fontSize: 10, width: 50 }}>{t.tx('位置', 'Placement')}</span>
              {['', 'popup', 'banner', 'floating', 'system_top'].map(p => (
                <button key={'p' + p}
                        className={'chip ' + (placementFilter === p ? 'active' : '')}
                        style={{ fontSize: 10 }}
                        onClick={() => setPlacementFilter(p)}>
                  {p === '' ? t.tx('全部', 'All') : p}
                </button>
              ))}
            </div>
            <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap', alignItems: 'center' }}>
              <span className="text-faint" style={{ fontSize: 10, width: 50 }}>{t.tx('频率', 'Frequency')}</span>
              {['', 'once', 'daily', 'always'].map(f => (
                <button key={'f' + f}
                        className={'chip ' + (freqFilter === f ? 'active' : '')}
                        style={{ fontSize: 10 }}
                        onClick={() => setFreqFilter(f)}>
                  {f === '' ? t.tx('全部', 'All') : f}
                </button>
              ))}
            </div>
          </div>

          <div className="tbl-scroll">
            <table className="tbl tbl-stack">
              <thead>
                <tr>
                  <th>Code</th>
                  <th>{t.tx('标题', 'Title')}</th>
                  <th>{t.tx('位置', 'Placement')}</th>
                  <th className="center">P</th>
                  <th>{t.tx('状态', 'Status')}</th>
                  <th>{t.tx('频率', 'Frequency')}</th>
                  <th>{t.tx('排期', 'Schedule')}</th>
                  <th className="right">{t.tx('操作', 'Actions')}</th>
                </tr>
              </thead>
              <tbody>
                {!listData && !listErr && (
                  <tr><td colSpan={8} style={{ textAlign: 'center', padding: 32, color: 'var(--text-faint)', fontSize: 11 }}>{t.tx('加载中…', 'Loading…')}</td></tr>
                )}
                {listData && items.length === 0 && (
                  <tr><td colSpan={8} style={{ textAlign: 'center', padding: 32, color: 'var(--text-faint)', fontSize: 11 }}>{t.tx('没有符合条件的公告', 'No announcements match')}</td></tr>
                )}
                {items.map(a => {
                  const sel = a.id === expandedId;
                  return (
                    <tr key={a.id}
                        onClick={() => setExpandedId(sel ? null : a.id)}
                        style={{ cursor: 'pointer', background: sel ? 'var(--bg-inset)' : '' }}>
                      <td data-label="Code" className="mono">{a.code}</td>
                      <td data-label={t.tx('标题', 'Title')} title={a.title}>{_annTrunc(a.title, 30)}</td>
                      <td data-label={t.tx('位置', 'Placement')}><span className={'chip ' + _annPlacementColor(a.placement)} style={{ fontSize: 10 }}>{a.placement}</span></td>
                      <td data-label="P" className="center tabular">{a.priority}</td>
                      <td data-label={t.tx('状态', 'Status')}><span className={'badge ' + _annStatusColor(a.status)} style={{ fontSize: 10 }}>{a.status}</span></td>
                      <td data-label={t.tx('频率', 'Frequency')} className="muted">{a.frequency}</td>
                      <td data-label={t.tx('排期', 'Schedule')} className="muted" style={{ fontSize: 10 }}>
                        {a.start_at ? _annFmtTime(a.start_at).slice(5, 16) : '—'}<br />
                        <span className="text-faint">→ {a.end_at ? _annFmtTime(a.end_at).slice(5, 16) : '—'}</span>
                      </td>
                      <td data-label={t.tx('操作', 'Actions')} className="right" onClick={(e) => e.stopPropagation()}>
                        <div className="tbl-actions">
                          <button className="btn btn-sm" onClick={() => setEditing(a)}>{t.tx('编辑', 'Edit')}</button>
                          {(a.status === 'draft' || a.status === 'paused') && (
                            <button className="btn btn-sm" onClick={() => doPublish(a)}>{t.tx('发布', 'Publish')}</button>
                          )}
                          {(a.status === 'live' || a.status === 'scheduled') && (
                            <button className="btn btn-sm" onClick={() => doPause(a)}>{t.tx('暂停', 'Pause')}</button>
                          )}
                          {a.status !== 'ended' && (
                            <button className="btn btn-sm btn-danger" onClick={() => doDelete(a)}>{t.tx('删除', 'Delete')}</button>
                          )}
                        </div>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>

        {/* 右 40%：详情面板 */}
        {expandedId && (() => {
          const a = items.find(x => x.id === expandedId) || allItems.find(x => x.id === expandedId);
          if (!a) return (
            <div className="card" style={{ padding: 16, fontSize: 11, color: 'var(--text-faint)' }}>
              {t.tx('所选公告已不在当前结果中', 'Selected announcement no longer in current results')}
              <button className="btn btn-sm" style={{ marginLeft: 8 }} onClick={() => setExpandedId(null)}>{t.tx('关闭', 'Close')}</button>
            </div>
          );
          return (
            <div className="card">
              <div className="card-h">
                <h3>{t.tx('详情', 'Detail')} · {a.code}</h3>
                <button className="icon-btn" onClick={() => setExpandedId(null)} style={{ fontSize: 14 }}>×</button>
              </div>
              <div style={{ padding: 14, display: 'flex', flexDirection: 'column', gap: 12 }}>
                <dl className="kv">
                  <dt>{t.tx('标题', 'Title')}</dt><dd>{a.title}</dd>
                  <dt>Code</dt><dd className="text-mono" style={{ fontSize: 11 }}>{a.code}</dd>
                  <dt>{t.tx('位置', 'Placement')}</dt><dd><span className={'chip ' + _annPlacementColor(a.placement)} style={{ fontSize: 10 }}>{a.placement}</span></dd>
                  <dt>{t.tx('优先级', 'Priority')}</dt><dd>{a.priority}</dd>
                  <dt>{t.tx('频率', 'Frequency')}</dt><dd>{a.frequency}</dd>
                  <dt>{t.tx('状态', 'Status')}</dt><dd><span className={'badge ' + _annStatusColor(a.status)} style={{ fontSize: 10 }}>{a.status}</span></dd>
                  <dt>{t.tx('开始', 'Start')}</dt><dd className="text-mono" style={{ fontSize: 10 }}>{_annFmtTime(a.start_at)}</dd>
                  <dt>{t.tx('结束', 'End')}</dt><dd className="text-mono" style={{ fontSize: 10 }}>{_annFmtTime(a.end_at)}</dd>
                  <dt>{t.tx('链接', 'Link')}</dt><dd className="text-mono" style={{ fontSize: 10, wordBreak: 'break-all' }}>{a.link || '—'}</dd>
                  <dt>{t.tx('图片', 'Image')}</dt><dd className="text-mono" style={{ fontSize: 10, wordBreak: 'break-all' }}>{a.image_url || '—'}</dd>
                  <dt>{t.tx('创建', 'Created')}</dt><dd className="text-faint text-mono" style={{ fontSize: 10 }}>{_annFmtTime(a.created_at)}</dd>
                  <dt>{t.tx('更新', 'Updated')}</dt><dd className="text-faint text-mono" style={{ fontSize: 10 }}>{_annFmtTime(a.updated_at)}</dd>
                </dl>

                <div>
                  <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>{t.tx('正文', 'Body')}</div>
                  <div style={{ fontSize: 12, lineHeight: 1.5, padding: 10, background: 'var(--bg-inset)', borderRadius: 6, whiteSpace: 'pre-wrap', wordBreak: 'break-word', maxHeight: 200, overflowY: 'auto' }}>
                    {a.body || <span className="text-faint">{t.tx('(无)', '(none)')}</span>}
                  </div>
                </div>

                <div>
                  <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>target_filter</div>
                  <pre style={{ fontSize: 10, padding: 10, background: 'var(--bg-inset)', borderRadius: 6, margin: 0, whiteSpace: 'pre-wrap', wordBreak: 'break-word', maxHeight: 160, overflowY: 'auto' }}>
                    {a.target_filter ? JSON.stringify(a.target_filter, null, 2) : t.tx('(默认 · 全部用户)', '(default · all users)')}
                  </pre>
                </div>

                <button className="btn btn-sm" onClick={() => setStatsFor(a)}>{t.tx('查看统计', 'View stats')}</button>
              </div>
            </div>
          );
        })()}
      </div>

      {showNew && (
        <AnnouncementFormModal
          mode="create"
          onClose={() => setShowNew(false)}
          onSaved={() => { setShowNew(false); refresh(); }}
          push={push}
          t={t}
        />
      )}
      {editing && (
        <AnnouncementFormModal
          mode="edit"
          initial={editing}
          onClose={() => setEditing(null)}
          onSaved={() => { setEditing(null); refresh(); }}
          push={push}
          t={t}
        />
      )}
      {statsFor && (
        <AnnouncementStatsModal
          ann={statsFor}
          onClose={() => setStatsFor(null)}
          push={push}
          t={t}
        />
      )}
    </div>
  );
}

// ─── Form modal: create / edit ──────────────────────────────────────────────
function AnnouncementFormModal({ mode, initial, onClose, onSaved, push, t }) {
  const ini = initial || {};
  const iniTF = ini.target_filter || {};
  const [form, setForm] = React.useState({
    title: ini.title || '',
    body: ini.body || '',
    image_url: ini.image_url || '',
    link: ini.link || '',
    placement: ini.placement || 'popup',
    priority: ini.priority != null ? ini.priority : 5,
    frequency: ini.frequency || 'once',
    start_at: _annFmtDtLocal(ini.start_at),
    end_at: _annFmtDtLocal(ini.end_at),
  });
  // target_filter 子状态
  const [tfTier, setTfTier] = React.useState(Array.isArray(iniTF.tier) ? iniTF.tier : []);
  const [tfMinRecharge, setTfMinRecharge] = React.useState(iniTF.min_recharge != null ? String(iniTF.min_recharge) : '');
  const [tfIsNewUser, setTfIsNewUser] = React.useState(!!iniTF.is_new_user);
  const [tfLastLogin, setTfLastLogin] = React.useState(iniTF.last_login_days_ago != null ? String(iniTF.last_login_days_ago) : '');

  const [busy, setBusy] = React.useState(false);
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  const toggleTier = (tier) => {
    setTfTier(arr => arr.includes(tier) ? arr.filter(x => x !== tier) : [...arr, tier]);
  };

  const submit = async () => {
    if (!form.title.trim()) { push(t.tx('标题必填', 'Title is required')); return; }
    setBusy(true);
    try {
      const tf = {};
      if (tfTier.length > 0) tf.tier = tfTier;
      if (tfMinRecharge !== '' && !isNaN(Number(tfMinRecharge))) tf.min_recharge = Number(tfMinRecharge);
      if (tfIsNewUser) tf.is_new_user = true;
      if (tfLastLogin !== '' && !isNaN(Number(tfLastLogin))) tf.last_login_days_ago = Number(tfLastLogin);

      const payload = {
        title: form.title.trim(),
        body: form.body,
        image_url: form.image_url.trim() || undefined,
        link: form.link.trim() || undefined,
        placement: form.placement,
        priority: Number(form.priority),
        frequency: form.frequency,
        start_at: form.start_at ? new Date(form.start_at).toISOString() : null,
        end_at: form.end_at ? new Date(form.end_at).toISOString() : null,
        target_filter: Object.keys(tf).length > 0 ? tf : null,
      };

      if (mode === 'create') {
        await _annFetch('/api/admin/announcements', { method: 'POST', body: JSON.stringify(payload) });
        push(t.tx('已创建草稿', 'Draft created'));
      } else {
        await _annFetch(`/api/admin/announcements/${initial.id}`, { method: 'PUT', body: JSON.stringify(payload) });
        push(t.tx('已保存', 'Saved'));
      }
      onSaved();
    } catch (e) {
      push((mode === 'create' ? t.tx('创建', 'Create') : t.tx('保存', 'Save')) + t.tx('失败: ', ' failed: ') + (e.body?.error || e.message || e));
    } finally {
      setBusy(false);
    }
  };

  return (
    <Modal open={true} onClose={onClose} title={mode === 'create' ? t.tx('新建公告', 'New Announcement') : t.tx('编辑公告 · ', 'Edit Announcement · ') + (initial.code || '')} width={680}
           footer={<>
             <button className="btn btn-sm" onClick={onClose}>{t.tx('取消', 'Cancel')}</button>
             <button className="btn btn-pri btn-sm" disabled={busy} onClick={submit}>
               {busy ? t.tx('提交中…', 'Submitting…') : (mode === 'create' ? t.tx('创建草稿', 'Create draft') : t.tx('保存', 'Save'))}
             </button>
           </>}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <_AnnField label={t.tx('标题 *', 'Title *')}>
          <input className="input" value={form.title} onChange={e => set('title', e.target.value)} placeholder={t.tx('例如：双倍充值返利上线', 'e.g. Double recharge rebate now live')} />
        </_AnnField>
        <_AnnField label={t.tx('正文', 'Body')}>
          <textarea className="textarea" rows={4} value={form.body} onChange={e => set('body', e.target.value)}
                    placeholder={t.tx('支持纯文本，前端可自行排版', 'Plain text supported, frontend handles layout')} style={{ width: '100%', resize: 'vertical' }} />
        </_AnnField>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <_AnnField label={t.tx('图片 URL', 'Image URL')} hint={t.tx('TODO: 真实上传', 'TODO: real upload')}>
            <input className="input" value={form.image_url} onChange={e => set('image_url', e.target.value)} placeholder="https://…" />
          </_AnnField>
          <_AnnField label={t.tx('跳转链接', 'Link')}>
            <input className="input" value={form.link} onChange={e => set('link', e.target.value)} placeholder={t.tx('/promo/xxx 或 https://…', '/promo/xxx or https://…')} />
          </_AnnField>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
          <_AnnField label={t.tx('位置 (placement)', 'Placement')}>
            <select className="select" value={form.placement} onChange={e => set('placement', e.target.value)}>
              <option value="popup">{t.tx('popup · 弹窗', 'popup · modal')}</option>
              <option value="banner">{t.tx('banner · 顶部横幅', 'banner · top banner')}</option>
              <option value="floating">{t.tx('floating · 悬浮', 'floating · float')}</option>
              <option value="system_top">{t.tx('system_top · 系统顶部', 'system_top · system top')}</option>
            </select>
          </_AnnField>
          <_AnnField label={t.tx('频率 (frequency)', 'Frequency')}>
            <select className="select" value={form.frequency} onChange={e => set('frequency', e.target.value)}>
              <option value="once">{t.tx('once · 每用户一次', 'once · once per user')}</option>
              <option value="daily">{t.tx('daily · 每日一次', 'daily · once per day')}</option>
              <option value="always">{t.tx('always · 每次展示', 'always · every time')}</option>
            </select>
          </_AnnField>
          <_AnnField label={t.tx('优先级: ', 'Priority: ') + form.priority + ' / 10'}>
            <input type="range" min={1} max={10} step={1}
                   value={form.priority} onChange={e => set('priority', e.target.value)}
                   style={{ width: '100%' }} />
          </_AnnField>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
          <_AnnField label={t.tx('开始时间 (start_at)', 'Start time (start_at)')}>
            <input className="input" type="datetime-local" value={form.start_at} onChange={e => set('start_at', e.target.value)} />
          </_AnnField>
          <_AnnField label={t.tx('结束时间 (end_at)', 'End time (end_at)')}>
            <input className="input" type="datetime-local" value={form.end_at} onChange={e => set('end_at', e.target.value)} />
          </_AnnField>
        </div>

        <div className="divider" />
        <div className="text-muted" style={{ fontSize: 11, fontWeight: 600 }}>{t.tx('target_filter（不填即对所有用户）', 'target_filter (empty = all users)')}</div>

        <_AnnField label={t.tx('tier (用户层级)', 'tier (user tier)')}>
          <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap' }}>
            {['bronze', 'silver', 'gold', 'platinum', 'diamond'].map(tier => (
              <button key={tier} type="button"
                      className={'chip ' + (tfTier.includes(tier) ? 'active' : '')}
                      onClick={() => toggleTier(tier)}>
                {tier}
              </button>
            ))}
          </div>
        </_AnnField>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
          <_AnnField label="min_recharge">
            <input className="input" type="number" min="0" value={tfMinRecharge}
                   onChange={e => setTfMinRecharge(e.target.value)} placeholder={t.tx('例：1000', 'e.g. 1000')} />
          </_AnnField>
          <_AnnField label="last_login_days_ago">
            <input className="input" type="number" min="0" value={tfLastLogin}
                   onChange={e => setTfLastLogin(e.target.value)} placeholder={t.tx('例：7', 'e.g. 7')} />
          </_AnnField>
          <_AnnField label="is_new_user">
            <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, paddingTop: 6 }}>
              <input type="checkbox" checked={tfIsNewUser} onChange={e => setTfIsNewUser(e.target.checked)} />
              {t.tx('仅新用户', 'New users only')}
            </label>
          </_AnnField>
        </div>
      </div>
    </Modal>
  );
}

// ─── Stats modal ────────────────────────────────────────────────────────────
function AnnouncementStatsModal({ ann, onClose, push, t }) {
  const [stats, setStats] = React.useState(null);
  const [err, setErr] = React.useState(null);

  React.useEffect(() => {
    let cancelled = false;
    _annFetch(`/api/admin/announcements/${ann.id}/stats`)
      .then(d => { if (!cancelled) setStats(d); })
      .catch(e => { if (!cancelled) setErr(e); });
    return () => { cancelled = true; };
  }, [ann.id]);

  const impressions = stats ? (stats.impressions ?? stats.views ?? 0) : 0;
  const clicks = stats ? (stats.clicks ?? 0) : 0;
  const closes = stats ? (stats.closes ?? stats.dismisses ?? 0) : 0;
  const ctr = impressions > 0 ? ((clicks / impressions) * 100).toFixed(2) + '%' : '—';

  return (
    <Modal open={true} onClose={onClose} title={t.tx('统计 · ', 'Stats · ') + (ann.title || ann.code)} width={520}
           footer={<button className="btn btn-sm" onClick={onClose}>{t.tx('关闭', 'Close')}</button>}>
      {!stats && !err && <div style={{ fontSize: 12, color: 'var(--text-faint)' }}>{t.tx('加载中…', 'Loading…')}</div>}
      {err && <div style={{ fontSize: 12, color: 'var(--danger)' }}>{t.tx('加载失败: ', 'Load failed: ')}{String(err.message || err)}</div>}
      {stats && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: 12 }}>
            <_AnnStatCell label={t.tx('曝光 (impressions)', 'Impressions')} value={impressions.toLocaleString()} />
            <_AnnStatCell label={t.tx('点击 (clicks)', 'Clicks')} value={clicks.toLocaleString()} color="var(--success)" />
            <_AnnStatCell label={t.tx('关闭 (closes)', 'Closes')} value={closes.toLocaleString()} color="var(--warning)" />
            <_AnnStatCell label="CTR" value={ctr} color="var(--accent-text)" />
          </div>
          <div className="divider" />
          <div>
            <div className="text-muted" style={{ fontSize: 11, marginBottom: 4 }}>{t.tx('原始响应', 'Raw response')}</div>
            <pre style={{ fontSize: 10, padding: 10, background: 'var(--bg-inset)', borderRadius: 6, margin: 0, whiteSpace: 'pre-wrap', wordBreak: 'break-word', maxHeight: 220, overflowY: 'auto' }}>
              {JSON.stringify(stats, null, 2)}
            </pre>
          </div>
        </div>
      )}
    </Modal>
  );
}

Object.assign(window, { AnnouncementsScreen, AnnouncementFormModal, AnnouncementStatsModal });
