// screens-bi.jsx — BI dashboard with five sub-tabs (funnel / retention / LTV / RFM / live KPI).
// Pure CSS visualisations — no chart libs. Backend lives under /api/admin/bi/*.

const _BI_NA = window.NebulaAdmin;
const _biFetch = _BI_NA.adminFetch;
const _biPoll  = _BI_NA.useAdminPoll;

// ── small helpers ───────────────────────────────────────────────────────────
function _biFmtMoney(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 _biFmtInt(n) {
  if (n == null || Number.isNaN(+n)) return '—';
  return Number(n).toLocaleString();
}
function _biPct(n) {
  if (n == null) return '—';
  return Number(n).toFixed(1) + '%';
}

// shared sub-tab chip strip
function BISubTabs({ active, onChange, t }) {
  const tabs = [
    ['funnel',    t.tx('漏斗', 'Funnel')],
    ['retention', t.tx('留存', 'Retention')],
    ['ltv',       t.tx('LTV', 'LTV')],
    ['rfm',       t.tx('RFM', 'RFM')],
    ['live',      t.tx('实时大屏', 'Live')],
  ];
  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. Funnel ───────────────────────────────────────────────────────────────
function BIFunnel({ t }) {
  const [days, setDays] = React.useState(7);
  const [tick, setTick] = React.useState(0);
  const [data, err] = _biPoll(`/api/admin/bi/funnel?days=${days}&_=${tick}`, 60000, true);

  const steps = (data && data.steps) || [];
  const maxCount = steps.reduce((m, s) => Math.max(m, s.count || 0), 1);
  const overall = data ? data.overall_rate : null;

  const stepLabels = {
    landed:          t.tx('访问', 'Landed'),
    registered:      t.tx('注册', 'Registered'),
    first_recharge:  t.tx('首充', 'First recharge'),
    placed_bet:      t.tx('投注', 'Placed bet'),
    repeat_recharge: t.tx('复购', 'Repeat recharge'),
  };

  return (
    <div className="stack">
      <div className="card">
        <div className="card-h">
          <h3>{t.tx('转化漏斗', 'Conversion Funnel')}</h3>
          <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
            <span className="text-muted" style={{ fontSize: 11 }}>{t.tx('窗口', 'Window')}</span>
            {[1, 7, 30].map(d => (
              <button key={d}
                      className={'chip ' + (days === d ? 'active' : '')}
                      onClick={() => setDays(d)}
                      style={{ fontSize: 11 }}>
                {d}d
              </button>
            ))}
            <button className="btn btn-sm" onClick={() => setTick(x => x + 1)}>
              <Icons.refresh /> {t.tx('刷新', 'Refresh')}
            </button>
          </div>
        </div>
        <div className="card-body">
          <div style={{
            background: 'var(--bg-active)', padding: '14px 18px', borderRadius: 10,
            display: 'flex', alignItems: 'baseline', gap: 12, marginBottom: 18,
          }}>
            <span style={{ fontSize: 12, color: 'var(--text-muted)' }}>
              {t.tx('总转化率（访问→复购）', 'Overall conv. (landed → repeat)')}
            </span>
            <span style={{ fontSize: 28, fontWeight: 700, letterSpacing: '-0.02em' }}>
              {overall == null ? '—' : overall.toFixed(2) + '%'}
            </span>
          </div>

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

          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {steps.map((s, i) => {
              const w = Math.max(8, (s.count / maxCount) * 100);
              const hue = 264 - i * 14;
              return (
                <div key={s.id} style={{ position: 'relative' }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: 'var(--text-muted)', marginBottom: 4 }}>
                    <span>{stepLabels[s.id] || s.label}</span>
                    {i > 0 && <span>{t.tx('环比', 'vs prev')} {_biPct(s.rate_from_prev)}</span>}
                  </div>
                  <div style={{ height: 38, background: 'var(--bg-active)', borderRadius: 8, overflow: 'hidden' }}>
                    <div style={{
                      width: w + '%', height: '100%',
                      background: `linear-gradient(90deg, oklch(0.62 0.18 ${hue}), oklch(0.55 0.16 ${hue + 20}))`,
                      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                      padding: '0 14px', color: '#fff', fontWeight: 600,
                    }}>
                      <span style={{ fontSize: 14 }}>{_biFmtInt(s.count)}</span>
                      <span style={{ fontSize: 12, opacity: 0.85 }}>
                        {i === 0 ? t.tx('入口', 'top') : _biPct(s.rate_from_prev)}
                      </span>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

// ── 2. Retention heatmap ────────────────────────────────────────────────────
function BIRetention({ t }) {
  const [tick, setTick] = React.useState(0);
  const [data, err] = _biPoll(`/api/admin/bi/retention?_=${tick}`, 60000, true);

  const cohorts = (data && data.cohorts) || [];
  // Show most-recent 14 days, ordered newest-first for display.
  const rows = cohorts.slice(-14).reverse();
  const cols = [
    { key: 'd1',  label: 'D1' },
    { key: 'd3',  label: 'D3' },
    { key: 'd7',  label: 'D7' },
    { key: 'd14', label: 'D14' },
    { key: 'd30', label: 'D30' },
  ];

  return (
    <div className="card">
      <div className="card-h">
        <h3>{t.tx('留存矩阵（近 14 天 cohorts）', 'Retention (last 14d cohorts)')}</h3>
        <button className="btn btn-sm" onClick={() => setTick(x => x + 1)}>
          <Icons.refresh /> {t.tx('刷新', 'Refresh')}
        </button>
      </div>
      <div className="card-body">
        {err && <div style={{ color: 'var(--danger)', fontSize: 12, marginBottom: 10 }}>
          {t.tx('加载失败：', 'Load failed: ')}{String(err.message || err)}
        </div>}
        {rows.length === 0 ? (
          <div className="text-faint" style={{ fontSize: 12, padding: '20px 0' }}>
            {t.tx('暂无 cohort 数据', 'No cohort data yet')}
          </div>
        ) : (
          <div className="tbl-scroll">
          <table className="tbl-stack" style={{ width: '100%', borderCollapse: 'separate', borderSpacing: 4 }}>
            <thead>
              <tr style={{ fontSize: 11, color: 'var(--text-muted)' }}>
                <th style={{ textAlign: 'left', padding: '4px 8px', minWidth: 100 }}>{t.tx('注册日期', 'Cohort')}</th>
                <th style={{ textAlign: 'right', padding: '4px 8px' }}>{t.tx('规模', 'Size')}</th>
                {cols.map(c => (
                  <th key={c.key} style={{ textAlign: 'center', padding: '4px 8px' }}>{c.label}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {rows.map(c => (
                <tr key={c.date}>
                  <td data-label={t.tx('注册日期', 'Cohort')} style={{ fontSize: 12, padding: '4px 8px', whiteSpace: 'nowrap' }}>{c.date}</td>
                  <td data-label={t.tx('规模', 'Size')} style={{ fontSize: 12, padding: '4px 8px', textAlign: 'right', color: 'var(--text-muted)' }}>{c.size}</td>
                  {cols.map(col => {
                    const rate = c.rates && c.rates[col.key];
                    const absCount = c[col.key.toUpperCase()] != null ? c[col.key.toUpperCase()] : c[col.key];
                    const r = Number(rate) || 0;
                    const opacity = Math.max(0.08, Math.min(1, r / 60));
                    const tip = t.tx(
                      `${c.date} · ${col.label} · ${absCount}/${c.size}`,
                      `${c.date} · ${col.label} · ${absCount}/${c.size}`,
                    );
                    return (
                      <td key={col.key} data-label={col.label} title={tip} style={{
                        padding: 0,
                        textAlign: 'center',
                      }}>
                        <div style={{
                          background: `oklch(0.62 0.18 264 / ${opacity})`,
                          color: r > 25 ? '#fff' : 'var(--text)',
                          padding: '8px 6px',
                          borderRadius: 4,
                          fontSize: 11.5,
                          fontWeight: 600,
                          minWidth: 54,
                        }}>
                          {r > 0 ? r.toFixed(1) + '%' : '—'}
                        </div>
                      </td>
                    );
                  })}
                </tr>
              ))}
            </tbody>
          </table>
          </div>
        )}
      </div>
    </div>
  );
}

// ── 3. LTV ──────────────────────────────────────────────────────────────────
function BILTV({ t }) {
  const [days, setDays] = React.useState(90);
  const [tick, setTick] = React.useState(0);
  const [data, err] = _biPoll(`/api/admin/bi/ltv?days=${days}&_=${tick}`, 60000, true);

  const bands = (data && data.bands) || [];
  const top   = (data && data.top)   || [];
  const maxBand = bands.reduce((m, b) => Math.max(m, b.count || 0), 1);

  return (
    <div className="stack">
      <div className="card">
        <div className="card-h">
          <h3>{t.tx('LTV 分布', 'LTV Distribution')}</h3>
          <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
            <span className="text-muted" style={{ fontSize: 11 }}>{t.tx('窗口', 'Window')}</span>
            {[30, 90, 180].map(d => (
              <button key={d}
                      className={'chip ' + (days === d ? 'active' : '')}
                      onClick={() => setDays(d)}
                      style={{ fontSize: 11 }}>{d}d</button>
            ))}
            <button className="btn btn-sm" onClick={() => setTick(x => x + 1)}>
              <Icons.refresh /> {t.tx('刷新', 'Refresh')}
            </button>
          </div>
        </div>
        <div className="card-body">
          {err && <div style={{ color: 'var(--danger)', fontSize: 12 }}>
            {t.tx('加载失败：', 'Load failed: ')}{String(err.message || err)}
          </div>}
          <div className="text-muted" style={{ fontSize: 11.5, marginBottom: 14 }}>
            {t.tx('用户总数', 'Total users')}: <b style={{ color: 'var(--text)' }}>{_biFmtInt(data && data.total_users)}</b>
          </div>
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 14, height: 200, padding: '0 8px' }}>
            {bands.map((b, i) => {
              const h = Math.max(4, (b.count / maxBand) * 170);
              const hue = 264 - i * 30;
              return (
                <div key={b.id} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 }}>
                  <div style={{ fontSize: 12, fontWeight: 600 }}>{_biFmtInt(b.count)}</div>
                  <div style={{
                    width: '70%', height: h,
                    background: `linear-gradient(180deg, oklch(0.65 0.18 ${hue}), oklch(0.5 0.14 ${hue}))`,
                    borderRadius: '6px 6px 0 0',
                  }} />
                  <div style={{ fontSize: 11, fontWeight: 600 }}>{b.label}</div>
                  <div style={{ fontSize: 10, color: 'var(--text-muted)' }}>{_biFmtMoney(b.total_value)}</div>
                </div>
              );
            })}
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-h">
          <h3>{t.tx('Top 20 预测 LTV', 'Top 20 predicted LTV')}</h3>
        </div>
        <div className="card-body" style={{ padding: 0 }}>
          <div className="tbl-scroll">
          <table className="tbl tbl-stack" style={{ width: '100%' }}>
            <thead>
              <tr>
                <th style={{ textAlign: 'left' }}>#</th>
                <th style={{ textAlign: 'left' }}>{t.tx('用户', 'User')}</th>
                <th style={{ textAlign: 'right' }}>{t.tx('累计充值', 'Total recharge')}</th>
                <th style={{ textAlign: 'right' }}>{t.tx('活跃天数', 'Days active')}</th>
                <th style={{ textAlign: 'right' }}>{t.tx('预测 LTV', 'Predicted LTV')}</th>
                <th style={{ textAlign: 'center' }}>{t.tx('档位', 'Band')}</th>
              </tr>
            </thead>
            <tbody>
              {top.length === 0 ? (
                <tr><td colSpan={6} style={{ textAlign: 'center', padding: 20, color: 'var(--text-faint)', fontSize: 12 }}>
                  {t.tx('暂无数据', 'No data')}
                </td></tr>
              ) : top.map((u, i) => (
                <tr key={u.user_id}>
                  <td data-label="#" className="muted">{i + 1}</td>
                  <td data-label={t.tx('用户', 'User')}>
                    <div style={{ fontWeight: 500 }}>{u.name}</div>
                    <div style={{ fontSize: 10, color: 'var(--text-faint)' }}>{u.user_id}</div>
                  </td>
                  <td data-label={t.tx('累计充值', 'Total recharge')} style={{ textAlign: 'right' }}>{_biFmtMoney(u.total_recharge)}</td>
                  <td data-label={t.tx('活跃天数', 'Days active')} style={{ textAlign: 'right', color: 'var(--text-muted)' }}>{u.days_active}d</td>
                  <td data-label={t.tx('预测 LTV', 'Predicted LTV')} style={{ textAlign: 'right', fontWeight: 600 }}>{_biFmtMoney(u.predicted_ltv)}</td>
                  <td data-label={t.tx('档位', 'Band')} style={{ textAlign: 'center' }}><span className="badge accent">{u.band}</span></td>
                </tr>
              ))}
            </tbody>
          </table>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── 4. RFM ──────────────────────────────────────────────────────────────────
function BIRFM({ t }) {
  const [days, setDays] = React.useState(30);
  const [tick, setTick] = React.useState(0);
  const [active, setActive] = React.useState(null);
  const [data, err] = _biPoll(`/api/admin/bi/rfm?days=${days}&_=${tick}`, 60000, true);

  const segments = (data && data.segments) || [];
  const usersBy  = (data && data.users_by_segment) || {};

  const segHue = {
    champion: 35, loyal: 264, big_spender: 305, at_risk: 25,
    hibernating: 230, new: 145, promising: 80, others: 0,
  };

  return (
    <div className="stack">
      <div className="card">
        <div className="card-h">
          <h3>{t.tx('RFM 分群', 'RFM Segments')}</h3>
          <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
            <span className="text-muted" style={{ fontSize: 11 }}>{t.tx('窗口', 'Window')}</span>
            {[7, 30, 90].map(d => (
              <button key={d}
                      className={'chip ' + (days === d ? 'active' : '')}
                      onClick={() => setDays(d)}
                      style={{ fontSize: 11 }}>{d}d</button>
            ))}
            <button className="btn btn-sm" onClick={() => setTick(x => x + 1)}>
              <Icons.refresh /> {t.tx('刷新', 'Refresh')}
            </button>
          </div>
        </div>
        <div className="card-body">
          {err && <div style={{ color: 'var(--danger)', fontSize: 12, marginBottom: 8 }}>
            {t.tx('加载失败：', 'Load failed: ')}{String(err.message || err)}
          </div>}
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
            {segments.map(s => {
              const hue = segHue[s.id] != null ? segHue[s.id] : 200;
              const isActive = active === s.id;
              return (
                <div key={s.id}
                     onClick={() => setActive(isActive ? null : s.id)}
                     style={{
                       padding: '10px 14px', borderRadius: 10, cursor: 'pointer',
                       background: isActive
                         ? `oklch(0.6 0.18 ${hue})`
                         : `oklch(0.95 0.04 ${hue})`,
                       color: isActive ? '#fff' : `oklch(0.4 0.16 ${hue})`,
                       border: `1px solid oklch(0.55 0.18 ${hue} / 0.4)`,
                       minWidth: 130, display: 'flex', flexDirection: 'column', gap: 2,
                     }}>
                  <div style={{ fontSize: 11.5, fontWeight: 600 }}>{s.label}</div>
                  <div style={{ fontSize: 20, fontWeight: 700, letterSpacing: '-0.02em' }}>{_biFmtInt(s.count)}</div>
                  <div style={{ fontSize: 10.5, opacity: 0.8 }}>{_biFmtMoney(s.total_value)}</div>
                </div>
              );
            })}
          </div>
        </div>
      </div>

      {active && (
        <div className="card">
          <div className="card-h">
            <h3>
              {t.tx('分群成员', 'Segment members')} · {segments.find(s => s.id === active)?.label || active}
            </h3>
            <button className="btn btn-sm" onClick={() => setActive(null)}>×</button>
          </div>
          <div className="card-body" style={{ padding: 0 }}>
            <div className="tbl-scroll">
            <table className="tbl tbl-stack" style={{ width: '100%' }}>
              <thead>
                <tr>
                  <th style={{ textAlign: 'left' }}>{t.tx('用户', 'User')}</th>
                  <th style={{ textAlign: 'center' }}>R</th>
                  <th style={{ textAlign: 'center' }}>F</th>
                  <th style={{ textAlign: 'center' }}>M</th>
                  <th style={{ textAlign: 'right' }}>{t.tx('累计价值', 'Value')}</th>
                </tr>
              </thead>
              <tbody>
                {(usersBy[active] || []).length === 0 ? (
                  <tr><td colSpan={5} style={{ textAlign: 'center', padding: 18, color: 'var(--text-faint)', fontSize: 12 }}>
                    {t.tx('该分群暂无用户', 'No users in this segment')}
                  </td></tr>
                ) : (usersBy[active] || []).map(u => (
                  <tr key={u.id}>
                    <td data-label={t.tx('用户', 'User')}>
                      <div style={{ fontWeight: 500 }}>{u.name}</div>
                      <div style={{ fontSize: 10, color: 'var(--text-faint)' }}>{u.id}</div>
                    </td>
                    <td data-label="R" style={{ textAlign: 'center' }}>{u.R}</td>
                    <td data-label="F" style={{ textAlign: 'center' }}>{u.F}</td>
                    <td data-label="M" style={{ textAlign: 'center' }}>{u.M}</td>
                    <td data-label={t.tx('累计价值', 'Value')} style={{ textAlign: 'right', fontWeight: 600 }}>{_biFmtMoney(u.value)}</td>
                  </tr>
                ))}
              </tbody>
            </table>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ── 5. Live KPI big-screen ──────────────────────────────────────────────────
function BILive({ t }) {
  const [data, err] = _biPoll('/api/admin/bi/kpi-live', 5000, true);
  const d = data || {};
  const lm = d.last_min || {};

  const cardStyle = {
    flex: 1, minWidth: 220,
    padding: '22px 24px', borderRadius: 14,
    background: 'rgba(255,255,255,0.06)',
    border: '1px solid rgba(255,255,255,0.08)',
    backdropFilter: 'blur(8px)',
  };
  const numStyle = { fontSize: 44, fontWeight: 700, letterSpacing: '-0.02em', color: '#fff', lineHeight: 1.05 };
  const labelStyle = { fontSize: 11.5, color: 'rgba(255,255,255,0.7)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 };

  return (
    <div style={{
      margin: '-16px',
      padding: 28,
      background: 'radial-gradient(circle at 20% -10%, oklch(0.3 0.12 264) 0%, oklch(0.12 0.02 270) 55%)',
      borderRadius: 16,
      color: '#fff',
      minHeight: 'calc(100vh - 120px)',
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: 22 }}>
        <div>
          <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-0.01em' }}>
            {t.tx('Nebula 实时大屏', 'Nebula Live Dashboard')}
          </div>
          <div style={{ fontSize: 12, color: 'rgba(255,255,255,0.65)', marginTop: 4 }}>
            {t.tx('每 5 秒刷新', 'Refresh every 5s')} · {d.now ? new Date(d.now).toLocaleString() : '—'}
          </div>
        </div>
        {err && <span style={{ fontSize: 11, color: 'oklch(0.7 0.18 25)' }}>
          {t.tx('连接异常', 'Connection error')}
        </span>}
      </div>

      <div style={{ display: 'flex', gap: 14, flexWrap: 'wrap', marginBottom: 18 }}>
        <div style={cardStyle}>
          <div style={labelStyle}>{t.tx('今日营收', 'Today revenue')}</div>
          <div style={numStyle}>{_biFmtMoney(d.today_revenue)}</div>
        </div>
        <div style={cardStyle}>
          <div style={labelStyle}>{t.tx('今日新用户', 'New users')}</div>
          <div style={numStyle}>{_biFmtInt(d.today_new_users)}</div>
        </div>
        <div style={cardStyle}>
          <div style={labelStyle}>{t.tx('今日活跃', 'Active users')}</div>
          <div style={numStyle}>{_biFmtInt(d.today_active_users)}</div>
        </div>
        <div style={cardStyle}>
          <div style={labelStyle}>{t.tx('今日投注笔数', 'Bets today')}</div>
          <div style={numStyle}>{_biFmtInt(d.today_bets)}</div>
        </div>
      </div>

      <div style={{ display: 'flex', gap: 14, flexWrap: 'wrap', marginBottom: 18 }}>
        <div style={{ ...cardStyle, flex: 2 }}>
          <div style={labelStyle}>{t.tx('近 1 分钟', 'Last minute')}</div>
          <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginTop: 6 }}>
            <span style={{ padding: '6px 14px', borderRadius: 999, background: 'oklch(0.7 0.16 145 / 0.18)', color: 'oklch(0.85 0.16 145)', fontSize: 13, fontWeight: 600 }}>
              {t.tx('充值', 'Recharges')} {lm.recharges || 0}
            </span>
            <span style={{ padding: '6px 14px', borderRadius: 999, background: 'oklch(0.7 0.16 264 / 0.18)', color: 'oklch(0.85 0.14 264)', fontSize: 13, fontWeight: 600 }}>
              {t.tx('投注', 'Bets')} {lm.bets || 0}
            </span>
            <span style={{ padding: '6px 14px', borderRadius: 999, background: 'oklch(0.7 0.16 35 / 0.18)', color: 'oklch(0.85 0.16 35)', fontSize: 13, fontWeight: 600 }}>
              {t.tx('提现', 'Withdraws')} {lm.withdraws || 0}
            </span>
          </div>
        </div>
        <div style={{ ...cardStyle, flex: 1 }}>
          <div style={labelStyle}>{t.tx('在线直播间', 'Live rooms')}</div>
          <div style={{ ...numStyle, fontSize: 32 }}>{_biFmtInt(d.live_rooms_online)}</div>
        </div>
        <div style={{ ...cardStyle, flex: 1 }}>
          <div style={labelStyle}>{t.tx('热门彩种', 'Hot lottery')}</div>
          <div style={{ ...numStyle, fontSize: 28 }}>{d.hot_lottery || '—'}</div>
          <div style={{ fontSize: 11, color: 'rgba(255,255,255,0.6)', marginTop: 4 }}>
            {t.tx('派彩率', 'Payout ratio')}: {d.today_payout_ratio != null ? (d.today_payout_ratio * 100).toFixed(1) + '%' : '—'}
          </div>
        </div>
      </div>

      <div style={cardStyle}>
        <div style={labelStyle}>{t.tx('告警', 'Alarms')}</div>
        {(!d.alarms || d.alarms.length === 0) ? (
          <div style={{ color: 'oklch(0.85 0.16 145)', fontSize: 13 }}>
            {t.tx('一切正常', 'All clear')}
          </div>
        ) : (
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 6 }}>
            {d.alarms.map((a, i) => {
              const bg = a.level === 'high' ? 'oklch(0.5 0.2 25)'
                       : a.level === 'warn' ? 'oklch(0.55 0.18 75)'
                       : 'oklch(0.45 0.12 230)';
              return (
                <span key={i} style={{
                  padding: '8px 16px', borderRadius: 8, background: bg, color: '#fff', fontSize: 13, fontWeight: 600,
                }}>
                  {a.text}
                </span>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
}

// ── Root ────────────────────────────────────────────────────────────────────
function BIScreen({ t, push }) {
  const [tab, setTab] = React.useState('funnel');

  return (
    <div className="stack">
      <div className="page-h">
        <div>
          <h1>{t.tx('数据 BI', 'BI Analytics')}</h1>
          <div className="sub">
            {t.tx(
              '漏斗 · 留存 · LTV · RFM · 实时大屏 — 一站式增长分析',
              'Funnel · Retention · LTV · RFM · Live KPI — growth analytics',
            )}
          </div>
        </div>
      </div>

      <BISubTabs active={tab} onChange={setTab} t={t} />

      {tab === 'funnel'    && <BIFunnel    t={t} />}
      {tab === 'retention' && <BIRetention t={t} />}
      {tab === 'ltv'       && <BILTV       t={t} />}
      {tab === 'rfm'       && <BIRFM       t={t} />}
      {tab === 'live'      && <BILive      t={t} />}
    </div>
  );
}

window.BIScreen = BIScreen;
