// screens-ops.jsx — Operations toolkit.
// Five sub-tabs: one-screen ops / cron / bulk-grant / bulk-push / daily report.
// All endpoints under /api/admin/ops/* + /api/admin/bi/kpi-live for the
// at-a-glance pane.

const _OPS_NA = window.NebulaAdmin;
const _opsFetch = _OPS_NA.adminFetch;
const _opsPoll  = _OPS_NA.useAdminPoll;

function _opsField({ label, children }) {
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 4, fontSize: 12 }}>
      <span style={{ color: 'var(--text-muted)' }}>{label}</span>
      {children}
    </label>
  );
}

function _opsFmtMoney(n) {
  if (n == null || Number.isNaN(+n)) return '—';
  const v = Number(n);
  if (Math.abs(v) >= 10000) return '¥' + (v / 10000).toFixed(2) + 'w';
  return '¥' + v.toFixed(2);
}
function _opsFmtInt(n) {
  if (n == null || Number.isNaN(+n)) return '—';
  return Number(n).toLocaleString();
}
function _opsFmtTime(iso) {
  if (!iso) return '—';
  const d = new Date(iso);
  if (isNaN(d)) return iso;
  const pad = (n) => String(n).padStart(2, '0');
  return `${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}

// ── Sub-tab strip ───────────────────────────────────────────────────────────
function OpsSubTabs({ active, onChange, t }) {
  const tabs = [
    ['glance', t.tx('一屏运营', 'Glance')],
    ['cron',   t.tx('Cron 调度', 'Cron')],
    ['grant',  t.tx('批量发礼', 'Bulk Grant')],
    ['push',   t.tx('批量发推', 'Bulk Push')],
    ['report', t.tx('日报表',    'Daily Report')],
  ];
  return (
    <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
      {tabs.map(([id, label]) => (
        <button key={id}
                className={'chip ' + (active === id ? 'active' : '')}
                onClick={() => onChange(id)}
                style={{ fontSize: 12 }}>
          {label}
        </button>
      ))}
    </div>
  );
}

// ── 1. Glance: one-screen ops (KPI live + todos) ───────────────────────────
function OpsGlance({ t }) {
  const [tick, setTick] = React.useState(0);
  const [kpi, kpiErr] = _opsPoll(`/api/admin/bi/kpi-live?_=${tick}`, 5000);
  // Pull todos: KYC pending count + risk_alerts via the daily report
  // endpoint (cheap; one query each).
  const [report, reportErr] = _opsPoll(`/api/admin/ops/daily-report?_=${tick}`, 30000);

  const big = (label, value, sub) => (
    <div style={{
      background: 'var(--bg-active)', borderRadius: 12, padding: '18px 22px',
      display: 'flex', flexDirection: 'column', gap: 4, minWidth: 180,
    }}>
      <span style={{ fontSize: 11, color: 'var(--text-muted)', letterSpacing: '0.04em', textTransform: 'uppercase' }}>{label}</span>
      <span style={{ fontSize: 32, fontWeight: 700, letterSpacing: '-0.02em' }}>{value}</span>
      {sub && <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>{sub}</span>}
    </div>
  );

  return (
    <div className="stack">
      <div className="card">
        <div className="card-h">
          <h3>{t.tx('一屏运营 · 实时大屏', 'One-screen Ops · Live')}</h3>
          <button className="btn btn-sm" onClick={() => setTick(x => x + 1)}>
            <Icons.refresh /> {t.tx('刷新', 'Refresh')}
          </button>
        </div>
        <div className="card-body">
          {(kpiErr || reportErr) && <div className="text-faint" style={{ color: 'var(--danger)', fontSize: 12, marginBottom: 12 }}>
            {t.tx('加载失败', 'Load failed')}
          </div>}
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}>
            {big(t.tx('今日营收', "Today's revenue"), _opsFmtMoney(kpi && kpi.today_revenue))}
            {big(t.tx('新增注册', 'New signups'), _opsFmtInt(kpi && kpi.today_new_users))}
            {big(t.tx('活跃用户', 'Active'), _opsFmtInt(kpi && kpi.today_active_users))}
            {big(t.tx('当前在线房间', 'Rooms online'), _opsFmtInt(kpi && kpi.live_rooms_online))}
            {big(t.tx('今日 RTP', "Today's RTP"),
                 kpi && kpi.today_payout_ratio != null
                   ? (kpi.today_payout_ratio * 100).toFixed(1) + '%' : '—')}
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-h"><h3>{t.tx('待办', 'Todos')}</h3></div>
        <div className="card-body" style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}>
          {big(t.tx('KYC 待审', 'KYC pending'),  _opsFmtInt(report && report.risk && report.risk.kyc_pending))}
          {big(t.tx('风控告警', 'Risk alerts'),  _opsFmtInt(report && report.risk && report.risk.risk_alerts))}
          {big(t.tx('错误事件', 'Error events'), _opsFmtInt(report && report.risk && report.risk.error_events))}
        </div>
      </div>

      <div className="card">
        <div className="card-h"><h3>{t.tx('最近 1 分钟', 'Last minute')}</h3></div>
        <div className="card-body" style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}>
          {big(t.tx('充值笔数', 'Recharges'), _opsFmtInt(kpi && kpi.last_min && kpi.last_min.recharges))}
          {big(t.tx('投注笔数', 'Bets'),      _opsFmtInt(kpi && kpi.last_min && kpi.last_min.bets))}
          {big(t.tx('提现笔数', 'Withdraws'), _opsFmtInt(kpi && kpi.last_min && kpi.last_min.withdraws))}
        </div>
      </div>
    </div>
  );
}

// ── 2. Cron ────────────────────────────────────────────────────────────────
function OpsCron({ t, push }) {
  const [tick, setTick] = React.useState(0);
  const [data, err] = _opsPoll(`/api/admin/ops/cron?_=${tick}`, 10000);
  const [expanded, setExpanded] = React.useState(null);

  const togglePause = async (name, paused) => {
    const verb = paused ? 'resume' : 'pause';
    try {
      await _opsFetch(`/api/admin/ops/cron/${encodeURIComponent(name)}/${verb}`, { method: 'POST' });
      push((paused ? t.tx('已恢复 ', 'Resumed ') : t.tx('已暂停 ', 'Paused ')) + name);
      setTick(x => x + 1);
    } catch (e) {
      push(t.tx('操作失败：', 'Failed: ') + (e.message || e));
    }
  };

  const jobs = (data && data.jobs) || [];

  return (
    <div className="stack">
      <div className="card">
        <div className="card-h">
          <h3>{t.tx('Cron 调度', 'Cron Scheduler')}</h3>
          <button className="btn btn-sm" onClick={() => setTick(x => x + 1)}>
            <Icons.refresh /> {t.tx('刷新', 'Refresh')}
          </button>
        </div>
        <div className="card-body">
          {err && <div className="text-faint" style={{ color: 'var(--danger)', fontSize: 12 }}>
            {t.tx('加载失败：', 'Load failed: ')}{String(err.message || err)}
          </div>}
          <div style={{ fontSize: 11, color: 'var(--text-faint)', marginBottom: 8 }}>
            {t.tx('暂停/恢复仅记录状态，loop 仍按原间隔运行（待 P1 完善）',
                  'Pause/resume only records state; loops still run at their interval (P1 follow-up)')}
          </div>
          <div className="tbl-scroll">
          <table className="table tbl-stack">
            <thead>
              <tr>
                <th>{t.tx('任务名', 'Job')}</th>
                <th>{t.tx('频率', 'Schedule')}</th>
                <th>{t.tx('最近运行', 'Last run')}</th>
                <th>{t.tx('耗时', 'Dur')}</th>
                <th>{t.tx('状态', 'Status')}</th>
                <th>{t.tx('操作', 'Actions')}</th>
              </tr>
            </thead>
            <tbody>
              {jobs.map(j => {
                const last = (j.runs && j.runs[0]) || null;
                const open = expanded === j.name;
                return (
                  <React.Fragment key={j.name}>
                    <tr>
                      <td data-label={t.tx('任务名', 'Job')}><code style={{ fontSize: 11 }}>{j.name}</code></td>
                      <td data-label={t.tx('频率', 'Schedule')} style={{ fontSize: 11 }}>{j.schedule}</td>
                      <td data-label={t.tx('最近运行', 'Last run')} style={{ fontSize: 11 }}>{last ? _opsFmtTime(last.started_at) : '—'}</td>
                      <td data-label={t.tx('耗时', 'Dur')} style={{ fontSize: 11 }}>{last ? (last.duration_ms + ' ms') : '—'}</td>
                      <td data-label={t.tx('状态', 'Status')}>
                        <span style={{ fontSize: 11, color: j.paused ? 'var(--warning)' : 'var(--success)' }}>
                          {j.paused ? t.tx('已暂停', 'Paused') : t.tx('运行中', 'Running')}
                        </span>
                      </td>
                      <td data-label={t.tx('操作', 'Actions')}>
                        <button className="btn btn-sm" onClick={() => togglePause(j.name, j.paused)}>
                          {j.paused ? '▶' : '⏸'} {j.paused ? t.tx('恢复', 'Resume') : t.tx('暂停', 'Pause')}
                        </button>
                        <button className="btn btn-sm" style={{ marginLeft: 6 }}
                                onClick={() => setExpanded(open ? null : j.name)}>
                          {open ? t.tx('收起', 'Hide') : t.tx('详情', 'Detail')}
                        </button>
                      </td>
                    </tr>
                    {open && (
                      <tr>
                        <td colSpan={6} style={{ background: 'var(--bg-active)' }}>
                          <div style={{ padding: '8px 12px' }}>
                            <div style={{ fontSize: 11, color: 'var(--text-muted)', marginBottom: 6 }}>
                              {t.tx('最近 5 次运行', 'Last 5 runs')}
                            </div>
                            {(j.runs || []).length === 0 && (
                              <div style={{ fontSize: 11, color: 'var(--text-faint)' }}>
                                {t.tx('暂无记录', 'No runs recorded yet')}
                              </div>
                            )}
                            {(j.runs || []).map(run => (
                              <div key={run.id} style={{
                                fontSize: 11, display: 'flex', gap: 12, padding: '4px 0',
                                borderBottom: '1px dashed var(--border)',
                              }}>
                                <span>{_opsFmtTime(run.started_at)}</span>
                                <span style={{ color: 'var(--text-muted)' }}>{run.duration_ms} ms</span>
                                {run.error && <span style={{ color: 'var(--danger)' }}>{run.error}</span>}
                                {!run.error && <span style={{ color: 'var(--success)' }}>ok</span>}
                              </div>
                            ))}
                          </div>
                        </td>
                      </tr>
                    )}
                  </React.Fragment>
                );
              })}
              {jobs.length === 0 && (
                <tr><td colSpan={6} style={{ textAlign: 'center', color: 'var(--text-faint)', fontSize: 12, padding: 24 }}>
                  {t.tx('暂无注册任务', 'No registered jobs')}
                </td></tr>
              )}
            </tbody>
          </table>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Filter form shared by bulk grant / bulk push ───────────────────────────
function OpsFilterForm({ filter, setFilter, t }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
      {_opsField({
        label: t.tx('用户层级', 'Tier'),
        children: (
          <select className="input" value={filter.tier || 'all'}
                  onChange={(e) => setFilter({ ...filter, tier: e.target.value })}>
            <option value="all">{t.tx('全部', 'All')}</option>
            <option value="vip">{t.tx('VIP / 金卡', 'VIP / Gold')}</option>
            <option value="non-vip">{t.tx('非 VIP', 'Non-VIP')}</option>
          </select>
        ),
      })}
      {_opsField({
        label: t.tx('近 N 天内活跃 (0 = 不限)', 'Active within N days (0 = any)'),
        children: (
          <input className="input" type="number" min="0" value={filter.active_days_lte || 0}
                 onChange={(e) => setFilter({ ...filter, active_days_lte: parseInt(e.target.value) || 0 })} />
        ),
      })}
      {_opsField({
        label: t.tx('累计充值下限 (¥)', 'Min total recharge (¥)'),
        children: (
          <input className="input" type="number" min="0" step="0.01" value={filter.min_recharge || 0}
                 onChange={(e) => setFilter({ ...filter, min_recharge: parseFloat(e.target.value) || 0 })} />
        ),
      })}
    </div>
  );
}

function OpsPreviewPane({ preview, t }) {
  if (!preview) return null;
  const list = (preview.preview || []);
  return (
    <div style={{
      marginTop: 12, padding: 12, background: 'var(--bg-active)', borderRadius: 8,
      fontSize: 12,
    }}>
      <div style={{ fontWeight: 600, marginBottom: 6 }}>
        {t.tx('命中：', 'Matched: ')}{preview.count}{' · '}
        {t.tx('预览前 10 个', 'Showing first 10')}
      </div>
      {list.length === 0 && <div style={{ color: 'var(--text-faint)' }}>{t.tx('无匹配用户', 'No match')}</div>}
      {list.slice(0, 10).map((u, i) => (
        <div key={u.id || i} style={{ display: 'flex', gap: 12, padding: '2px 0' }}>
          <code style={{ fontSize: 11 }}>{u.id}</code>
          <span>{u.name}</span>
        </div>
      ))}
    </div>
  );
}

// ── 3. Bulk grant ──────────────────────────────────────────────────────────
function OpsBulkGrant({ t, push }) {
  const [filter, setFilter] = React.useState({ tier: 'all', active_days_lte: 0, min_recharge: 0 });
  const [grant, setGrant] = React.useState({ gift_id: 'rocket', count: 1, note: '' });
  const [preview, setPreview] = React.useState(null);
  const [busy, setBusy] = React.useState(false);

  const runPreview = async () => {
    setBusy(true);
    try {
      const r = await _opsFetch('/api/admin/ops/bulk-grant', {
        method: 'POST',
        body: JSON.stringify({ filter, grant, dry_run: true }),
      });
      setPreview(r);
    } catch (e) { push(t.tx('预览失败：', 'Preview failed: ') + (e.message || e)); }
    finally { setBusy(false); }
  };

  const runGrant = async () => {
    if (!preview) { push(t.tx('请先预览', 'Preview first')); return; }
    if (!confirm(t.tx(`确认向 ${preview.count} 个用户发放？`, `Confirm grant to ${preview.count} users?`))) return;
    setBusy(true);
    try {
      const r = await _opsFetch('/api/admin/ops/bulk-grant', {
        method: 'POST',
        body: JSON.stringify({ filter, grant }),
      });
      push(t.tx(`已发放 ${r.count} 份（ref: ${r.ref}）`, `Granted ${r.count} (ref: ${r.ref})`));
      setPreview(null);
    } catch (e) { push(t.tx('发放失败：', 'Grant failed: ') + (e.message || e)); }
    finally { setBusy(false); }
  };

  return (
    <div className="card">
      <div className="card-h"><h3>{t.tx('批量发礼', 'Bulk Gift Grant')}</h3></div>
      <div className="card-body stack">
        <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
          {t.tx('筛选用户', 'Filter users')}
        </div>
        <OpsFilterForm filter={filter} setFilter={setFilter} t={t} />
        <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 8 }}>
          {t.tx('礼物配置', 'Gift')}
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
          {_opsField({ label: t.tx('礼物 ID', 'Gift ID'),
            children: <input className="input" value={grant.gift_id}
              onChange={(e) => setGrant({ ...grant, gift_id: e.target.value })} /> })}
          {_opsField({ label: t.tx('数量', 'Count'),
            children: <input className="input" type="number" min="1" value={grant.count}
              onChange={(e) => setGrant({ ...grant, count: parseInt(e.target.value) || 1 })} /> })}
          {_opsField({ label: t.tx('备注', 'Note'),
            children: <input className="input" value={grant.note}
              onChange={(e) => setGrant({ ...grant, note: e.target.value })} /> })}
        </div>
        <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
          <button className="btn" onClick={runPreview} disabled={busy}>
            {t.tx('预览', 'Preview')}
          </button>
          <button className="btn btn-pri" onClick={runGrant} disabled={busy || !preview}>
            {t.tx('确认发放', 'Confirm grant')}
          </button>
        </div>
        <OpsPreviewPane preview={preview} t={t} />
      </div>
    </div>
  );
}

// ── 4. Bulk push ───────────────────────────────────────────────────────────
function OpsBulkPush({ t, push }) {
  const [filter, setFilter] = React.useState({ tier: 'all', active_days_lte: 7, min_recharge: 0 });
  const [pushBody, setPushBody] = React.useState({ title: '', body: '', deeplink: '' });
  const [preview, setPreview] = React.useState(null);
  const [busy, setBusy] = React.useState(false);

  const runPreview = async () => {
    setBusy(true);
    try {
      const r = await _opsFetch('/api/admin/ops/bulk-push', {
        method: 'POST',
        body: JSON.stringify({ filter, push: pushBody, dry_run: true }),
      });
      setPreview(r);
    } catch (e) { push(t.tx('预览失败：', 'Preview failed: ') + (e.message || e)); }
    finally { setBusy(false); }
  };

  const runPush = async () => {
    if (!pushBody.title || !pushBody.body) { push(t.tx('标题/内容必填', 'Title/body required')); return; }
    if (!preview) { push(t.tx('请先预览', 'Preview first')); return; }
    if (!confirm(t.tx(`确认推送 ${preview.count} 个用户？`, `Confirm push to ${preview.count} users?`))) return;
    setBusy(true);
    try {
      const r = await _opsFetch('/api/admin/ops/bulk-push', {
        method: 'POST',
        body: JSON.stringify({ filter, push: pushBody }),
      });
      push(t.tx(`已推送 ${r.count} 条`, `Pushed ${r.count}`));
      setPreview(null);
    } catch (e) { push(t.tx('推送失败：', 'Push failed: ') + (e.message || e)); }
    finally { setBusy(false); }
  };

  return (
    <div className="card">
      <div className="card-h"><h3>{t.tx('批量推送', 'Bulk Push')}</h3></div>
      <div className="card-body stack">
        <div style={{ fontSize: 11, color: 'var(--text-muted)' }}>
          {t.tx('筛选用户', 'Filter users')}
        </div>
        <OpsFilterForm filter={filter} setFilter={setFilter} t={t} />
        <div style={{ fontSize: 11, color: 'var(--text-muted)', marginTop: 8 }}>
          {t.tx('推送内容', 'Push content')}
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 12 }}>
          {_opsField({ label: t.tx('标题', 'Title'),
            children: <input className="input" value={pushBody.title}
              onChange={(e) => setPushBody({ ...pushBody, title: e.target.value })} /> })}
          {_opsField({ label: t.tx('Deeplink', 'Deeplink'),
            children: <input className="input" value={pushBody.deeplink}
              placeholder="nebula://promo/spring"
              onChange={(e) => setPushBody({ ...pushBody, deeplink: e.target.value })} /> })}
        </div>
        {_opsField({ label: t.tx('正文', 'Body'),
          children: <textarea className="input" rows={3} value={pushBody.body}
            onChange={(e) => setPushBody({ ...pushBody, body: e.target.value })} /> })}
        <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
          <button className="btn" onClick={runPreview} disabled={busy}>
            {t.tx('预览', 'Preview')}
          </button>
          <button className="btn btn-pri" onClick={runPush} disabled={busy || !preview}>
            {t.tx('确认推送', 'Confirm push')}
          </button>
        </div>
        <OpsPreviewPane preview={preview} t={t} />
      </div>
    </div>
  );
}

// ── 5. Daily Report ────────────────────────────────────────────────────────
function OpsDailyReport({ t, push }) {
  const today = new Date().toISOString().slice(0, 10);
  const [date, setDate] = React.useState(today);
  const [data, setData] = React.useState(null);
  const [busy, setBusy] = React.useState(false);

  const generate = async () => {
    setBusy(true);
    try {
      const r = await _opsFetch(`/api/admin/ops/daily-report?date=${encodeURIComponent(date)}`);
      setData(r);
    } catch (e) { push(t.tx('生成失败：', 'Failed: ') + (e.message || e)); }
    finally { setBusy(false); }
  };

  const exportCSV = () => {
    const token = _OPS_NA.getToken();
    // Build a one-shot download via fetch + Blob (cleaner than a raw <a> with
    // bearer auth missing).
    fetch(`/api/admin/ops/daily-report?date=${encodeURIComponent(date)}&format=csv`, {
      headers: token ? { Authorization: 'Bearer ' + token } : {},
    }).then(r => r.blob()).then(blob => {
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url; a.download = `nebula-daily-${date}.csv`;
      document.body.appendChild(a); a.click(); a.remove();
      URL.revokeObjectURL(url);
    }).catch(e => push(t.tx('导出失败：', 'Export failed: ') + (e.message || e)));
  };

  return (
    <div className="card">
      <div className="card-h"><h3>{t.tx('日报表', 'Daily Report')}</h3></div>
      <div className="card-body stack">
        <div style={{ display: 'flex', gap: 8, alignItems: 'flex-end' }}>
          {_opsField({ label: t.tx('日期 (UTC)', 'Date (UTC)'),
            children: <DateRangePicker t={t} mode="single" date={date} onChange={(d) => setDate(d)} size="sm" /> })}
          <button className="btn btn-pri" onClick={generate} disabled={busy}>
            {busy ? t.tx('生成中…', 'Generating…') : t.tx('生成', 'Generate')}
          </button>
          <button className="btn" onClick={exportCSV}>
            {t.tx('导出 CSV', 'Export CSV')}
          </button>
        </div>
        {data && (
          <div style={{
            background: 'var(--bg-active)', padding: 14, borderRadius: 8,
            fontSize: 12, fontFamily: 'monospace', whiteSpace: 'pre-wrap',
            maxHeight: 480, overflow: 'auto',
          }}>
            {JSON.stringify(data, null, 2)}
          </div>
        )}
      </div>
    </div>
  );
}

// ── Root ────────────────────────────────────────────────────────────────────
function OpsScreen({ t, push }) {
  const [tab, setTab] = React.useState('glance');
  return (
    <div className="stack">
      <div className="card">
        <div className="card-h">
          <h3>{t.p_ops || t.tx('运营工具', 'Ops Toolkit')}</h3>
          <OpsSubTabs active={tab} onChange={setTab} t={t} />
        </div>
      </div>
      {tab === 'glance' && <OpsGlance t={t} />}
      {tab === 'cron'   && <OpsCron   t={t} push={push} />}
      {tab === 'grant'  && <OpsBulkGrant t={t} push={push} />}
      {tab === 'push'   && <OpsBulkPush  t={t} push={push} />}
      {tab === 'report' && <OpsDailyReport t={t} push={push} />}
    </div>
  );
}

window.OpsScreen = OpsScreen;
