/* Admin views - Overview, Matches, Create, Settle, Draw. */

/* ============================================================
   OVERVIEW
   ============================================================ */
function StatCard({ label, value, accent = 'orange', delta }) {
  const colors = {
    orange: 'var(--orange)',
    ink:    'var(--ink)',
    green:  'var(--success)',
    grey:   'var(--grey-400)',
  };
  return (
    <div style={{
      background: '#fff', border: '1.5px solid var(--grey-200)',
      padding: '18px 20px', position: 'relative', overflow: 'hidden',
    }}>
      <div style={{
        position: 'absolute', top: 0, left: 0, bottom: 0, width: 4, background: colors[accent],
      }} />
      <div style={{ fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--grey-500)', fontWeight: 700 }}>
        {label}
      </div>
      <div className="font-display" style={{ fontSize: 32, lineHeight: 1, marginTop: 8, letterSpacing: '-0.02em', color: accent === 'green' ? colors.green : 'var(--ink)' }}>
        {value}
      </div>
      {delta && (
        <div style={{ marginTop: 6, fontSize: 12, color: 'var(--success)', fontWeight: 600 }}>
          {delta}
        </div>
      )}
    </div>
  );
}

/* Campaign-health signal palette */
const HEALTH_COLORS = { good: 'var(--success)', warn: '#d97706', bad: '#dc2626' };
const HEALTH_LABELS = { good: 'On track', warn: 'Needs attention', bad: 'Off track' };

function SignalRow({ label, value, status, note, action }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12, padding: '12px 0', borderBottom: '1px solid var(--grey-100)' }}>
      <span style={{ width: 10, height: 10, borderRadius: '50%', background: HEALTH_COLORS[status], marginTop: 4, flexShrink: 0 }} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
          <span style={{ fontWeight: 700, fontSize: 13 }}>{label}</span>
          <span className="font-mono" style={{ fontSize: 12.5, fontWeight: 700, color: HEALTH_COLORS[status] }}>{value}</span>
        </div>
        <div style={{ fontSize: 12.5, color: 'var(--grey-600)', marginTop: 2, lineHeight: 1.45 }}>{note}</div>
        {action && status !== 'good' && (
          <div style={{ fontSize: 11.5, color: HEALTH_COLORS[status], fontWeight: 700, marginTop: 5, display: 'flex', gap: 5, alignItems: 'flex-start' }}>
            <span style={{ flexShrink: 0 }}>→</span><span>{action}</span>
          </div>
        )}
      </div>
    </div>
  );
}


function AdminOverview({ ctx }) {
  const preds = ctx.livePredictions;
  const open = ctx.matchesState.filter(m => m.status === 'OPEN');
  const closed = ctx.matchesState.filter(m => m.status === 'CLOSED');
  const settled = ctx.matchesState.filter(m => m.status === 'SETTLED');

  const [billData, setBillData] = useState(null);
  const [smsStats, setSmsStats] = useState(null);
  const [expandOutlet, setExpandOutlet] = useState(null);

  useEffect(() => {
    let active = true;
    function loadData() {
      Promise.all([
        fetch('/api/get-bill-data', { headers: { 'x-admin-key': ctx.adminToken } })
          .then(r => r.json()),
        fetch('/api/sms-automation?action=stats', { headers: { 'x-admin-key': ctx.adminToken } })
          .then(r => r.json())
          .catch(() => null),
      ]).then(([bd, sms]) => {
        if (active) {
          if (bd && bd.billUsage) setBillData(bd);
          if (sms && sms.counts) setSmsStats(sms.counts);
        }
      });
    }
    loadData();
    const id = setInterval(loadData, 20000);
    return () => { active = false; clearInterval(id); };
  }, [ctx.adminToken]);

  const billUsage = (billData && billData.billUsage) || [];
  const billEntries = (billData && billData.billEntries) || [];
  const outletStats = (billData && billData.outletStats) || [];

  const todayStart = new Date();
  todayStart.setHours(0, 0, 0, 0);
  const todayCount = preds.filter(p => p.submittedAt >= todayStart.getTime()).length;

  const uniquePlayers = new Set(preds.map(p => p.customerPhone).filter(Boolean)).size;
  const totalBills = billUsage.length;
  const votedBills = billUsage.filter(u => (u.used_votes || 0) > 0).length;
  const activationPct = totalBills ? Math.round((votedBills / totalBills) * 100) : 0;
  const maxVotes = billUsage.reduce((s, u) => s + (u.max_votes || 0), 0);
  const usedVotes = billUsage.reduce((s, u) => s + (u.used_votes || 0), 0);

  const DAY = 86400000;
  const campaignStart = new Date(2026, 5, 10);
  campaignStart.setHours(0, 0, 0, 0);
  const campaignDay = Math.max(1, Math.floor((Date.now() - campaignStart.getTime()) / DAY) + 1);
  const dayCount = Math.min(14, campaignDay);
  const daily = [];
  for (let i = dayCount - 1; i >= 0; i--) {
    const dStart = todayStart.getTime() - i * DAY;
    const n = preds.filter(p => p.submittedAt >= dStart && p.submittedAt < dStart + DAY).length;
    daily.push({ label: new Date(dStart).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }), n });
  }

  const last3 = daily.slice(-3).reduce((s, d) => s + d.n, 0);
  const prev3 = daily.slice(-6, -3).reduce((s, d) => s + d.n, 0);

  const verdict = (last3 === 0 && prev3 === 0) ? 'bad' : (last3 >= prev3 * 1.1 || prev3 === 0) ? 'good' : (last3 <= prev3 * 0.7) ? 'bad' : 'warn';

  const badCount = (last3 <= prev3 * 0.7 || (activationPct < 35) || (totalBills - votedBills > totalBills * 0.4)) ? 1 : 0;

  // Today's progress
  var billsIssuedToday = 0;
  var billsActivatedToday = 0;
  var predictionsToday = 0;
  if (billData) {
    billsIssuedToday = billEntries.filter(e => e.created_at && new Date(e.created_at) >= todayStart).length;
    billsActivatedToday = billUsage.filter(u => (u.used_votes || 0) > 0 && u.created_at && new Date(u.created_at) >= todayStart).length;
  }
  predictionsToday = preds.filter(p => p.submittedAt >= todayStart.getTime()).length;
  var activationTodayPct = billsIssuedToday > 0 ? Math.round((billsActivatedToday / billsIssuedToday) * 100) : 0;

  // Unique people who have bills/predictions
  var peopleBounded = new Set(billUsage.map(u => u.customer_phone || u.phone).filter(Boolean)).size;

  const recentActivity = preds.slice(0, 6).map(p => ({
    t: p.submittedAt,
    text: `${p.customerName || 'Someone'} picked ${p.matchLabel} → ${p.pick}`,
    outlet: p.outlet,
  }));

  const votePct = maxVotes ? Math.round((usedVotes / maxVotes) * 100) : 0;

  return (
    <AdminSection
      title="Campaign command centre"
      sub={`Day ${campaignDay} · ${open.length} open · ${closed.length} closed · ${settled.length} settled`}
      right={
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          <AdminBtn kind="outline" icon="calendar" onClick={() => ctx.goTab('create')}>New match</AdminBtn>
          <AdminBtn kind="primary" icon="message" onClick={() => ctx.goTab('sms')}>SMS Center</AdminBtn>
          <AdminBtn kind="primary" icon="trophy" onClick={() => ctx.goTab('draw')}>Lucky draw</AdminBtn>
        </div>
      }
    >
      {/* LAYER 1: Campaign Status (compact) */}
      <div style={{ background: '#fff', border: '1px solid var(--grey-200)', borderRadius: 10, padding: 14, marginBottom: 16 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
          <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink)' }}>Day {campaignDay}</div>
          <div style={{ display: 'inline-block', background: verdict === 'good' ? '#d1fae5' : verdict === 'warn' ? '#fef3c7' : '#fee2e2', color: verdict === 'good' ? '#065f46' : verdict === 'warn' ? '#92400e' : '#7f1d1d', fontSize: 10, fontWeight: 800, padding: '4px 10px', borderRadius: 5, letterSpacing: '0.04em' }}>
            {verdict === 'good' ? '✓ ON TRACK' : verdict === 'warn' ? '⚠ ATTENTION' : '✕ CRITICAL'}
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 10 }}>
          <div style={{ textAlign: 'center', padding: '8px 0', borderRight: '1px solid var(--grey-100)' }}>
            <div style={{ fontSize: 18, fontWeight: 800, color: 'var(--ink)' }}>{billsIssuedToday}</div>
            <div style={{ fontSize: 8, fontWeight: 700, color: 'var(--grey-400)', marginTop: 2 }}>BILLS TODAY</div>
          </div>
          <div style={{ textAlign: 'center', padding: '8px 0', borderRight: '1px solid var(--grey-100)' }}>
            <div style={{ fontSize: 18, fontWeight: 800, color: activationTodayPct >= 60 ? '#22c55e' : activationTodayPct >= 35 ? '#f59e0b' : '#ef4444' }}>{billData ? activationTodayPct : '—'}%</div>
            <div style={{ fontSize: 8, fontWeight: 700, color: 'var(--grey-400)', marginTop: 2 }}>ACTIVATED</div>
          </div>
          <div style={{ textAlign: 'center', padding: '8px 0' }}>
            <div style={{ fontSize: 18, fontWeight: 800, color: 'var(--ink)' }}>{predictionsToday}</div>
            <div style={{ fontSize: 8, fontWeight: 700, color: 'var(--grey-400)', marginTop: 2 }}>PREDICTIONS</div>
          </div>
        </div>
      </div>

      {/* LAYER 2: Daily Trend (quick view, moved to top) */}
      {daily.length > 0 && (
        <div style={{ background: '#fff', border: '1px solid var(--grey-200)', borderRadius: 10, padding: 14, marginBottom: 16 }}>
          <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--grey-500)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 10 }}>Daily trend (14 days)</div>
          <div style={{ display: 'flex', alignItems: 'flex-end', gap: 2, height: 60 }}>
            {daily.slice(-14).map(d => {
              var peak = Math.max(...daily.map(x => x.n), 1);
              return (
                <div key={d.label} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-end', gap: 1, height: '100%' }}>
                  <span style={{ fontSize: 7, color: 'var(--grey-600)' }}>{d.n > 0 ? d.n : ''}</span>
                  <div style={{ width: '100%', height: Math.max(2, (d.n / peak) * 40), background: '#22c55e', borderRadius: 1 }} />
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* LAYER 3: Participation Funnel (simplified) */}
      {billData && (
        <div style={{ background: '#fff', border: '1px solid var(--grey-200)', borderRadius: 10, padding: 14, marginBottom: 16 }}>
          <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--grey-500)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 12 }}>Participation Funnel</div>
          {[
            { label: 'Bills issued', count: totalBills, pct: 100, color: 'var(--ink)' },
            { label: 'People bounded', count: peopleBounded, pct: totalBills ? Math.round((peopleBounded / totalBills) * 100) : 0, color: 'var(--ink)' },
            { label: 'Vote utilization', count: usedVotes, pct: votePct, color: votePct >= 50 ? '#22c55e' : votePct >= 25 ? '#f59e0b' : '#ef4444', sub: `of ${maxVotes} earned` },
          ].map((step, idx) => (
            <div key={step.label} style={{ marginBottom: 10 }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>
                <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink)' }}>{step.label}</span>
                <span style={{ fontSize: 11, fontWeight: 800, color: step.color, fontFamily: 'monospace' }}>{step.count} {step.sub ? <span style={{ fontWeight: 600, color: 'var(--grey-400)' }}>({step.sub})</span> : <span>({step.pct}%)</span>}</span>
              </div>
              <div style={{ height: 20, background: 'var(--grey-100)', borderRadius: 3, overflow: 'hidden' }}>
                <div style={{ height: '100%', width: step.pct + '%', background: step.color, borderRadius: 3, transition: 'width 0.6s ease-out' }} />
              </div>
            </div>
          ))}
        </div>
      )}

      {/* LAYER 4: Outlet Performance (expanded metrics) */}
      {billData && outletStats.length > 0 && (
        <div style={{ background: '#fff', border: '1px solid var(--grey-200)', borderRadius: 10, padding: 14, marginBottom: 16 }}>
          <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--grey-500)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 12 }}>Outlet Performance</div>
          <div style={{ display: 'grid', gap: 8 }}>
            {outletStats.slice(0, 8).map(outlet => {
              var pct = outlet.totalBills ? Math.round((outlet.voted / outlet.totalBills) * 100) : 0;
              var color = pct >= 60 ? '#22c55e' : pct >= 35 ? '#f59e0b' : '#ef4444';
              var trend = pct >= 60 ? '↑ Strong' : pct >= 35 ? '→ Fair' : '↓ Low';
              return (
                <div key={outlet.outlet} style={{ paddingBottom: 8, borderBottom: '1px solid var(--grey-100)' }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 6 }}>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink)' }}>{outlet.outlet}</div>
                      <div style={{ fontSize: 10, color: color, fontWeight: 700, marginTop: 2 }}>{pct}% activation · {trend}</div>
                    </div>
                    <div style={{ textAlign: 'right', fontSize: 10, fontWeight: 700, color: 'var(--grey-600)' }}>
                      {outlet.totalBills} bills
                    </div>
                  </div>
                  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8, paddingBottom: 6 }}>
                    <div style={{ textAlign: 'center', padding: '6px 0', background: 'var(--grey-50)', borderRadius: 4 }}>
                      <div style={{ fontSize: 14, fontWeight: 800, color: '#22c55e' }}>{outlet.voted}</div>
                      <div style={{ fontSize: 8, fontWeight: 700, color: 'var(--grey-500)', marginTop: 1 }}>used bill</div>
                    </div>
                    <div style={{ textAlign: 'center', padding: '6px 0', background: '#e8f5e9', borderRadius: 4 }}>
                      <div style={{ fontSize: 14, fontWeight: 800, color: '#22c55e' }}>{pct}%</div>
                      <div style={{ fontSize: 8, fontWeight: 700, color: 'var(--grey-500)', marginTop: 1 }}>usage</div>
                    </div>
                    <div style={{ textAlign: 'center', padding: '6px 0', background: 'var(--grey-50)', borderRadius: 4 }}>
                      <div style={{ fontSize: 14, fontWeight: 800, color: '#f59e0b' }}>{outlet.notVoted}</div>
                      <div style={{ fontSize: 8, fontWeight: 700, color: 'var(--grey-500)', marginTop: 1 }}>silent</div>
                    </div>
                    <div style={{ textAlign: 'center', padding: '6px 0', background: 'var(--grey-50)', borderRadius: 4 }}>
                      <div style={{ fontSize: 14, fontWeight: 800, color: color }}>{outlet.totalBills}</div>
                      <div style={{ fontSize: 8, fontWeight: 700, color: 'var(--grey-500)', marginTop: 1 }}>total</div>
                    </div>
                  </div>
                  {outlet.notVoted > 0 && (
                    <button style={{ width: '100%', background: 'var(--orange)', color: '#fff', border: 'none', borderRadius: 4, padding: '6px 10px', fontSize: 10, fontWeight: 700, cursor: 'pointer' }} onClick={() => ctx.goTab('sms')}>Send reminder ({outlet.notVoted})</button>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* LAYER 5: Live Activity + Key Metrics */}
      <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 16 }}>
        <div style={{ background: '#fff', border: '1px solid var(--grey-200)', borderRadius: 10, padding: 14 }}>
          <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--grey-500)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 10 }}>Live Activity</div>
          <div style={{ maxHeight: 100, overflowY: 'auto', display: 'grid', gap: 5 }}>
            {recentActivity.length === 0 && <div style={{ fontSize: 11, color: 'var(--grey-400)' }}>No activity yet</div>}
            {recentActivity.slice(0, 4).map((activity, i) => (
              <div key={i} style={{ fontSize: 10, color: 'var(--grey-600)', lineHeight: 1.3 }}>
                🎯 {activity.text}
              </div>
            ))}
            {smsStats && smsStats.sent > 0 && <div style={{ fontSize: 10, color: '#22c55e', fontWeight: 700 }}>✓ SMS sent {smsStats.sent}</div>}
          </div>
        </div>
        <div style={{ background: '#fff', border: '1px solid var(--grey-200)', borderRadius: 10, padding: 14 }}>
          <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--grey-500)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 10 }}>Key Metrics</div>
          <div style={{ display: 'grid', gap: 8 }}>
            <div>
              <div style={{ fontSize: 9, fontWeight: 700, color: 'var(--grey-400)', marginBottom: 2 }}>PLAYERS</div>
              <div style={{ fontSize: 16, fontWeight: 800, color: 'var(--ink)' }}>{uniquePlayers}</div>
            </div>
            <div>
              <div style={{ fontSize: 9, fontWeight: 700, color: 'var(--grey-400)', marginBottom: 2 }}>MOMENTUM</div>
              <div style={{ fontSize: 14, fontWeight: 800, color: last3 >= prev3 ? '#22c55e' : '#ef4444' }}>{last3}/{prev3}</div>
            </div>
          </div>
        </div>
      </div>
    </AdminSection>
  );
}

function AdminMatches({ ctx }) {
  const [q, setQ] = useState('');
  const [filter, setFilter] = useState('ALL');

  const filtered = ctx.matchesState.filter(m => {
    if (filter !== 'ALL' && m.status !== filter) return false;
    if (q) {
      const Q = q.toLowerCase();
      return (m.teamA.name + ' ' + m.teamB.name + ' ' + m.stage + ' ' + m.venue).toLowerCase().includes(Q);
    }
    return true;
  });

  const filters = ['ALL', 'OPEN', 'SCHEDULED', 'CLOSED', 'SETTLED'];
  const counts = filters.reduce((acc, f) => {
    acc[f] = f === 'ALL' ? ctx.matchesState.length : ctx.matchesState.filter(m => m.status === f).length;
    return acc;
  }, {});

  function fakeCsv(label) {
    ctx.setToast({ message: `CSV "${label}" queued for download.`, tone: 'info' });
  }
  function deleteMatch(id) {
    ctx.setMatchesState(s => s.filter(m => m.id !== id));
    ctx.setToast({ message: 'Match removed.', tone: 'success' });
  }

  return (
    <AdminSection
      title="All matches"
      sub="Schedule, settle, run draws, or export per-match prediction CSVs."
      right={
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          <AdminBtn kind="outline" icon="receipt" onClick={() => fakeCsv('all_predictions.csv')}>Export all predictions</AdminBtn>
          <AdminBtn kind="primary" icon="calendar" onClick={() => ctx.goTab('create')}>Schedule new</AdminBtn>
        </div>
      }
    >
      <Panel padding={0}>
        {/* Filter bar */}
        <div style={{
          padding: '14px 18px',
          display: 'flex', gap: 14, flexWrap: 'wrap', alignItems: 'center',
          borderBottom: '1px solid var(--grey-200)',
        }}>
          <div style={{ position: 'relative', flex: '1 1 240px', maxWidth: 320 }}>
            <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search by team, stage, venue..."
              style={{ ...inputStyle, paddingLeft: 36 }} />
            <svg style={{ position: 'absolute', left: 11, top: '50%', transform: 'translateY(-50%)' }}
              width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--grey-400)" strokeWidth="2" strokeLinecap="round">
              <circle cx="11" cy="11" r="7"/><path d="M21 21l-4-4"/>
            </svg>
          </div>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
            {filters.map(f => {
              const active = filter === f;
              return (
                <button key={f} onClick={() => setFilter(f)} style={{
                  background: active ? 'var(--ink)' : 'transparent',
                  color: active ? '#fff' : 'var(--grey-700)',
                  border: `1.5px solid ${active ? 'var(--ink)' : 'var(--grey-300)'}`,
                  padding: '7px 12px',
                  fontSize: 11.5, letterSpacing: '0.06em', textTransform: 'uppercase', fontWeight: 700,
                  cursor: 'pointer',
                  display: 'inline-flex', alignItems: 'center', gap: 6,
                }}>
                  {f}
                  <span style={{
                    background: active ? 'var(--orange)' : 'var(--grey-100)',
                    color: active ? '#fff' : 'var(--grey-600)',
                    padding: '1px 6px', fontSize: 10, borderRadius: 999,
                  }}>{counts[f]}</span>
                </button>
              );
            })}
          </div>
        </div>

        {/* Table */}
        <div style={{ overflowX: 'auto' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 880 }}>
            <thead>
              <tr style={{ background: 'var(--grey-50)' }}>
                <Th>Match</Th>
                <Th>Stage</Th>
                <Th>Kickoff</Th>
                <Th>Status</Th>
                <Th align="right">Predictions</Th>
                <Th align="right">Actions</Th>
              </tr>
            </thead>
            <tbody>
              {filtered.map(m => {
                const predCount = ctx.livePredictions.filter(p => p.matchId === m.id).length;
                return (
                  <tr key={m.id} style={{ borderTop: '1px solid var(--grey-100)' }}>
                    <Td>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                        <Flag code={m.teamA.flag} w={24} h={16} />
                        <span style={{ fontWeight: 700, fontSize: 13.5 }}>{m.teamA.name}</span>
                        <span style={{ color: 'var(--grey-400)', fontSize: 11 }}>vs</span>
                        <span style={{ fontWeight: 700, fontSize: 13.5 }}>{m.teamB.name}</span>
                        <Flag code={m.teamB.flag} w={24} h={16} />
                      </div>
                      <div style={{ fontSize: 11.5, color: 'var(--grey-500)', marginTop: 4 }}>{m.venue}</div>
                    </Td>
                    <Td><span style={{ fontSize: 12.5 }}>{m.stage}</span></Td>
                    <Td>
                      <div style={{ fontSize: 12.5 }}>{formatKickoff(m.kickoffAt)}</div>
                      {m.status === 'OPEN' && (
                        <div style={{ marginTop: 4 }}>
                          <Countdown to={m.kickoffMs} tone="light" size="sm" prefix="CLOSES" />
                        </div>
                      )}
                    </Td>
                    <Td><StatusBadge status={m.status} size="sm" /></Td>
                    <Td align="right">
                      <span className="font-display" style={{ fontSize: 18 }}>{predCount.toLocaleString()}</span>
                    </Td>
                    <Td align="right">
                      <div style={{ display: 'inline-flex', gap: 6 }}>
                        <IconBtn title="Download CSV" onClick={() => fakeCsv(`match_${m.id}_predictions.csv`)} icon="receipt" />
                        {m.status === 'CLOSED' && (
                          <IconBtn title="Settle" onClick={() => ctx.goTab('settle')} icon="check" tone="orange" />
                        )}
                        {m.status === 'SETTLED' && (
                          <IconBtn title="Run draw" onClick={() => ctx.goTab('draw')} icon="trophy" tone="orange" />
                        )}
                        <IconBtn title="Delete" onClick={() => deleteMatch(m.id)} icon="bolt" tone="danger" />
                      </div>
                    </Td>
                  </tr>
                );
              })}
              {filtered.length === 0 && (
                <tr><td colSpan="6" style={{ padding: 32, textAlign: 'center', color: 'var(--grey-500)' }}>No matches match those filters.</td></tr>
              )}
            </tbody>
          </table>
        </div>
      </Panel>
    </AdminSection>
  );
}

function Th({ children, align = 'left' }) {
  return (
    <th style={{
      padding: '12px 14px', textAlign: align,
      fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase',
      color: 'var(--grey-600)', fontWeight: 700,
    }}>{children}</th>
  );
}
function Td({ children, align = 'left', style: extraStyle }) {
  return <td style={{ padding: '14px', textAlign: align, verticalAlign: 'middle', ...extraStyle }}>{children}</td>;
}
function IconBtn({ icon, title, onClick, tone = 'default' }) {
  const palette = {
    default: { bg: '#fff',          fg: 'var(--grey-700)', bd: 'var(--grey-300)' },
    orange:  { bg: 'var(--orange-50)', fg: 'var(--orange-dark)', bd: 'var(--orange)' },
    danger:  { bg: '#fff',          fg: '#b91c1c',         bd: '#fecaca' },
  }[tone];
  return (
    <button onClick={onClick} title={title} style={{
      background: palette.bg, color: palette.fg, border: `1.5px solid ${palette.bd}`,
      padding: 7, cursor: 'pointer',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
    }}>
      <Icon name={icon} size={15} />
    </button>
  );
}

/* ============================================================
   CREATE MATCH
   ============================================================ */
function AdminCreate({ ctx }) {
  const teamKeys = Object.keys(TEAMS);
  const [teamA, setTeamA] = useState('');
  const [teamB, setTeamB] = useState('');
  const [kickoff, setKickoff] = useState('');
  const [stage, setStage] = useState('Group Stage');
  const [venue, setVenue] = useState('');

  const ok = teamA && teamB && teamA !== teamB && kickoff;

  function submit() {
    if (!ok) return;
    const ko = new Date(kickoff);
    const newMatch = {
      id: Math.max(...ctx.matchesState.map(m => m.id)) + 1,
      teamA: TEAMS[teamA], teamB: TEAMS[teamB],
      teamAKey: teamA, teamBKey: teamB,
      kickoffAt: ko, kickoffMs: ko.getTime(),
      stage, venue: venue || '-',
      status: ko.getTime() > Date.now() ? 'OPEN' : 'CLOSED',
      settled: null,
    };
    ctx.setMatchesState(s => [...s, newMatch]);
    ctx.setToast({ message: `Match created: ${newMatch.teamA.name} vs ${newMatch.teamB.name}`, tone: 'success' });
    setTeamA(''); setTeamB(''); setKickoff(''); setStage('Group Stage'); setVenue('');
  }

  return (
    <AdminSection
      title="Schedule a new match"
      sub="Pick the two teams, set the kickoff, and choose the stage. Predictions auto-open 24h before kickoff."
    >
      <div className="admin-2col" style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: 18 }}>
        <Panel title="Match details">
          <div style={{ display: 'grid', gap: 16 }}>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
              <FormSelect label="Team A" value={teamA} onChange={setTeamA} options={teamKeys.map(k => ({ value: k, label: TEAMS[k].name }))} placeholder="Select team A" />
              <FormSelect label="Team B" value={teamB} onChange={setTeamB} options={teamKeys.filter(k => k !== teamA).map(k => ({ value: k, label: TEAMS[k].name }))} placeholder="Select team B" />
            </div>
            <div>
              <FormLabel>Kickoff (your local time)</FormLabel>
              <input type="datetime-local" value={kickoff} onChange={(e) => setKickoff(e.target.value)} style={inputStyle} />
            </div>
            <FormSelect label="Stage" value={stage} onChange={setStage} options={STAGES.map(s => ({ value: s, label: s }))} />
            <div>
              <FormLabel>Venue <span style={{ color: 'var(--grey-400)', fontWeight: 400 }}>(optional)</span></FormLabel>
              <input value={venue} onChange={(e) => setVenue(e.target.value)} placeholder="e.g. MetLife Stadium, New Jersey" style={inputStyle} />
            </div>
            <div style={{ display: 'flex', gap: 10, marginTop: 6 }}>
              <AdminBtn kind="primary" icon="check" onClick={submit} disabled={!ok}>Create match</AdminBtn>
              <AdminBtn kind="ghost" onClick={() => { setTeamA(''); setTeamB(''); setKickoff(''); setVenue(''); }}>Reset</AdminBtn>
            </div>
          </div>
        </Panel>

        <Panel title="Preview" action={<span style={{ fontSize: 11, color: 'var(--grey-500)', letterSpacing: '0.06em', textTransform: 'uppercase' }}>How it'll look</span>}>
          {(teamA && teamB) ? (
            <div style={{
              border: '2px solid var(--grey-200)', padding: 18, background: 'var(--grey-50)',
            }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 14 }}>
                <StatusBadge status="OPEN" size="sm" />
                <span className="font-mono" style={{ fontSize: 11, color: 'var(--grey-500)' }}>{stage}</span>
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr auto 1fr', alignItems: 'center', gap: 14 }}>
                <div style={{ textAlign: 'center' }}>
                  <Flag code={TEAMS[teamA].flag} w={48} h={32} />
                  <div className="font-display" style={{ fontSize: 14, marginTop: 6 }}>{TEAMS[teamA].name}</div>
                </div>
                <VSHex size={32} />
                <div style={{ textAlign: 'center' }}>
                  <Flag code={TEAMS[teamB].flag} w={48} h={32} />
                  <div className="font-display" style={{ fontSize: 14, marginTop: 6 }}>{TEAMS[teamB].name}</div>
                </div>
              </div>
              <div style={{ marginTop: 14, fontSize: 12, color: 'var(--grey-600)' }}>
                {kickoff ? formatKickoff(new Date(kickoff)) : 'Set a kickoff time...'}
                {venue && <> · {venue}</>}
              </div>
            </div>
          ) : (
            <div style={{ color: 'var(--grey-500)', fontSize: 13.5, padding: 20, textAlign: 'center' }}>
              Pick two teams to see the preview.
            </div>
          )}
        </Panel>
      </div>

      <style>{`
        @media (max-width: 900px) {
          .admin-2col { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </AdminSection>
  );
}

function FormLabel({ children }) {
  return <div style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 700, marginBottom: 6 }}>{children}</div>;
}
function FormSelect({ label, value, onChange, options, placeholder }) {
  return (
    <div>
      <FormLabel>{label}</FormLabel>
      <select value={value} onChange={(e) => onChange(e.target.value)} style={inputStyle}>
        {placeholder && <option value="">- {placeholder} -</option>}
        {options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
      </select>
    </div>
  );
}

/* ============================================================
   SETTLE
   ============================================================ */
function AdminSettle({ ctx }) {
  const candidates = ctx.matchesState.filter(m => m.status === 'CLOSED' || m.status === 'OPEN');
  const [mid, setMid] = useState('');
  const [result, setResult] = useState(null); // 'A' | 'DRAW' | 'B'
  const [scoreA, setScoreA] = useState('');
  const [scoreB, setScoreB] = useState('');
  const match = candidates.find(m => m.id === Number(mid));

  const [saving, setSaving] = useState(false);

  async function settle() {
    if (!match || !result || saving) return;
    const winner = result === 'A' ? match.teamA.name : result === 'B' ? match.teamB.name : 'Draw';
    setSaving(true);
    try {
      const r = await fetch('/api/settle-match', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-admin-key': ctx.adminToken },
        body: JSON.stringify({
          match_id:    match.id,
          match_label: `${match.teamA.name} vs ${match.teamB.name}`,
          winner_pick: result,
          score_a:     Number(scoreA) || 0,
          score_b:     Number(scoreB) || 0,
        }),
      });
      const data = await r.json();
      if (!r.ok) {
        ctx.setToast({ message: data.error || 'Could not settle match.', tone: 'error' });
        setSaving(false);
        return;
      }
      // Update local view
      ctx.setMatchesState(s => s.map(m => m.id === match.id ? {
        ...m, status: 'SETTLED',
        settled: {
          winner: result === 'A' ? match.teamAKey : result === 'B' ? match.teamBKey : null,
          scoreA: Number(scoreA) || 0, scoreB: Number(scoreB) || 0,
          draw: result === 'DRAW',
        }
      } : m));
      const g = data.graded || {};
      ctx.setToast({
        message: `Settled: ${match.teamA.name} ${scoreA || 0}-${scoreB || 0} ${match.teamB.name} · ${winner} · ${g.correct || 0}/${g.total || 0} correct`,
        tone: 'success',
      });
      setMid(''); setResult(null); setScoreA(''); setScoreB('');
    } catch (e) {
      ctx.setToast({ message: 'Network error. Try again.', tone: 'error' });
    }
    setSaving(false);
  }

  // ── Auto-sync results from FIFA via Firecrawl ──
  const [syncing, setSyncing] = useState(false);
  async function syncFifa() {
    if (syncing) return;
    setSyncing(true);
    try {
      const r = await fetch('/api/sync-fifa-results', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-admin-key': ctx.adminToken },
      });
      const d = await r.json();
      if (!r.ok) {
        ctx.setToast({ message: d.error || 'FIFA sync failed.', tone: 'error' });
      } else if (d.settledCount > 0) {
        ctx.setToast({ message: `FIFA sync: ${d.settledCount} match(es) auto-settled from live results.`, tone: 'success' });
      } else {
        ctx.setToast({ message: `FIFA sync done. No newly-finished matches found (${d.finishedCount} finished total).`, tone: 'info' });
      }
    } catch (e) {
      ctx.setToast({ message: 'FIFA sync network error.', tone: 'error' });
    }
    setSyncing(false);
  }

  return (
    <AdminSection
      title="Settle a match"
      sub="Pull live results from FIFA automatically, or enter a result manually. Predictions auto-grade and unlock the lucky-draw."
    >
      <Panel style={{ marginBottom: 16 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 14, flexWrap: 'wrap' }}>
          <div>
            <div className="font-display" style={{ fontSize: 15, color: 'var(--ink)' }}>Auto-settle from FIFA</div>
            <div style={{ fontSize: 12.5, color: 'var(--grey-500)', marginTop: 3 }}>
              Scrapes fifa.com live scores and settles every finished match in one click.
            </div>
          </div>
          <AdminBtn kind="primary" icon="bolt" disabled={syncing} onClick={syncFifa}>
            {syncing ? 'Syncing from FIFA...' : 'Sync results from FIFA'}
          </AdminBtn>
        </div>
      </Panel>
      <Panel>
        {candidates.length === 0 ? (
          <div style={{ color: 'var(--grey-500)', padding: 20, textAlign: 'center' }}>
            No matches awaiting a result.
          </div>
        ) : (
          <>
            <div style={{ maxWidth: 480 }}>
              <FormSelect label="Pick a match" value={mid} onChange={setMid} placeholder="Select"
                options={candidates.map(m => ({
                  value: String(m.id),
                  label: `${m.teamA.name} vs ${m.teamB.name} · ${m.stage} · ${m.status}`,
                }))}
              />
            </div>

            {match && (
              <div style={{ marginTop: 22 }}>
                <FormLabel>Final result</FormLabel>
                <div className="settle-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
                  <SettleBtn selected={result === 'A'} onClick={() => setResult('A')} kind="team" flag={match.teamA.flag} label={`${match.teamA.name} wins`} />
                  <SettleBtn selected={result === 'DRAW'} onClick={() => setResult('DRAW')} kind="draw" label="Draw" />
                  <SettleBtn selected={result === 'B'} onClick={() => setResult('B')} kind="team" flag={match.teamB.flag} label={`${match.teamB.name} wins`} />
                </div>

                <div style={{ marginTop: 22, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, maxWidth: 360 }}>
                  <div>
                    <FormLabel>{match.teamA.name} score</FormLabel>
                    <input type="number" min="0" value={scoreA} onChange={(e) => setScoreA(e.target.value)} className="font-mono" style={inputStyle} />
                  </div>
                  <div>
                    <FormLabel>{match.teamB.name} score</FormLabel>
                    <input type="number" min="0" value={scoreB} onChange={(e) => setScoreB(e.target.value)} className="font-mono" style={inputStyle} />
                  </div>
                </div>

                <div style={{ marginTop: 24, display: 'flex', gap: 10, flexWrap: 'wrap' }}>
                  <AdminBtn kind="primary" icon="check" disabled={!result || saving} onClick={settle}>{saving ? 'Settling...' : 'Mark match settled'}</AdminBtn>
                  <AdminBtn kind="ghost" onClick={() => { setMid(''); setResult(null); }}>Cancel</AdminBtn>
                </div>

                <div style={{
                  marginTop: 18, padding: '12px 14px', background: 'var(--orange-50)', border: '1.5px solid var(--orange-100)',
                  fontSize: 12.5, color: 'var(--ink)',
                }}>
                  ⚠ This action is irreversible. It will flag <strong>{ctx.livePredictions.filter(p => p.matchId === match.id).length}</strong> predictions
                  as correct / incorrect and unlock the lucky draw.
                </div>
              </div>
            )}
          </>
        )}
      </Panel>

      <style>{`
        @media (max-width: 700px) {
          .settle-grid { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </AdminSection>
  );
}

function SettleBtn({ selected, onClick, kind, flag, label }) {
  return (
    <button onClick={onClick} style={{
      background: selected ? 'var(--orange-50)' : '#fff',
      border: selected ? '2px solid var(--orange)' : '1px solid var(--grey-200)',
      borderRadius: 10,
      boxShadow: selected ? '0 4px 16px rgba(241,86,35,0.22)' : '0 2px 8px rgba(17,6,24,0.05)',
      padding: '18px 14px',
      display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10,
      cursor: 'pointer',
    }}>
      {kind === 'draw' ? (
        <div style={{ width: 56, height: 40, background: 'var(--ink)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Icon name="scale" size={22} color="var(--orange)" />
        </div>
      ) : (
        <Flag code={flag} w={48} h={32} />
      )}
      <span className="font-display" style={{ fontSize: 13.5, textAlign: 'center' }}>{label}</span>
    </button>
  );
}

/* ============================================================
   DRAW
   ============================================================ */
function AdminDraw({ ctx }) {
  /* ── prize-type config ── */
  const PRIZE_TYPES = [
    { key: 'matchday', label: 'Match Day',  slots: 2, icon: 'bolt',    color: '#f97316', sub: '2 winners per match day · all participants' },
    { key: 'weekly',   label: 'Weekly',     slots: 1, icon: 'trophy',  color: '#7c3aed', sub: '1 winner per week · all participants' },
    { key: 'campaign', label: 'Campaign',   slots: 1, icon: 'star',    color: '#16a34a', sub: '1 grand winner · correct predictions only' },
  ];

  const [prizeType, setPrizeType]         = useState('matchday');
  const [scope, setScope]                 = useState('');
  const [searchQ, setSearchQ]             = useState('');
  const [rolling, setRolling]             = useState(false);
  const [candidate, setCandidate]         = useState(null);
  const [savingWinner, setSavingWinner]   = useState(false);
  const [finalWinners, setFinalWinners]   = useState([]);
  const [loadingFinal, setLoadingFinal]   = useState(true);
  const [rollTick, setRollTick]           = useState(0);  // animation key

  /* ── load finalized winners ── */
  useEffect(() => {
    setLoadingFinal(true);
    fetch('/api/draw-winners', { headers: { 'x-admin-key': ctx.adminToken } })
      .then(r => r.json())
      .then(d => { setFinalWinners(Array.isArray(d) ? d : []); setLoadingFinal(false); })
      .catch(() => setLoadingFinal(false));
  }, [ctx.adminToken]);

  /* ── reset scope & candidate when prize type changes ── */
  useEffect(() => { setScope(''); setCandidate(null); setSearchQ(''); }, [prizeType]);

  /* ── matchday options (group by MVT date = UTC+5) ── */
  const matchdayOptions = useMemo(() => {
    const DAYS = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
    const MONTHS = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
    const byDate = {};
    ctx.matchesState.forEach(m => {
      const mvt = new Date(new Date(m.kickoffAt || m.kickoff).getTime() + 5 * 3600 * 1000);
      const key = mvt.toISOString().slice(0, 10);
      (byDate[key] || (byDate[key] = [])).push(m.id);
    });
    return Object.keys(byDate).sort().map((key, i) => {
      const d = new Date(key + 'T00:00:00Z');
      return {
        value: key,
        label: `Matchday ${i + 1} · ${DAYS[d.getUTCDay()]} ${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]}`,
        matchIds: byDate[key],
      };
    });
  }, [ctx.matchesState]);

  /* ── weekly options (fixed campaign weeks) ── */
  const weekOptions = useMemo(() => {
    // Fixed week boundaries (MVT dates, inclusive)
    const FIXED_WEEKS = [
      { value: 'week-1', label: 'Week 1 · Jun 10 – Jun 20', start: '2026-06-10', end: '2026-06-20' },
      { value: 'week-2', label: 'Week 2 · Jun 21 – Jun 27', start: '2026-06-21', end: '2026-06-27' },
      { value: 'week-3', label: 'Week 3 · Jun 28 – Jul 4',  start: '2026-06-28', end: '2026-07-04' },
      { value: 'week-4', label: 'Week 4 · Jul 5 – Jul 11',  start: '2026-07-05', end: '2026-07-11' },
      { value: 'week-5', label: 'Week 5 · Jul 12 – Jul 18', start: '2026-07-12', end: '2026-07-18' },
      { value: 'week-6', label: 'Week 6 · Jul 19 – Jul 20', start: '2026-07-19', end: '2026-07-20' },
    ];
    return FIXED_WEEKS.map(wk => {
      const startMs = new Date(wk.start + 'T00:00:00Z').getTime();
      const endMs   = new Date(wk.end   + 'T23:59:59Z').getTime();
      const matchIds = ctx.matchesState
        .filter(m => {
          const mvtMs = new Date(m.kickoffAt || m.kickoff).getTime() + 5 * 3600 * 1000;
          return mvtMs >= startMs && mvtMs <= endMs;
        })
        .map(m => m.id);
      return { value: wk.value, label: wk.label, matchIds };
    }).filter(wk => wk.matchIds.length > 0);
  }, [ctx.matchesState]);

  /* ── match ID set for current scope ── */
  const scopeMatchIds = useMemo(() => {
    if (prizeType === 'matchday') {
      const opt = matchdayOptions.find(o => o.value === scope);
      return new Set(opt ? opt.matchIds : []);
    }
    if (prizeType === 'weekly') {
      const opt = weekOptions.find(o => o.value === scope);
      return new Set(opt ? opt.matchIds : []);
    }
    return null; // campaign = all
  }, [prizeType, scope, matchdayOptions, weekOptions]);

  /* ── draw pool: unique participants for scope ── */
  const pool = useMemo(() => {
    if (!ctx.livePredictions) return [];
    const seen = {};
    const preds = ctx.livePredictions.filter(p => {
      if (p.isVoid) return false;
      if (prizeType === 'campaign') return p.isCorrect === true;
      if (scopeMatchIds && !scopeMatchIds.has(p.matchId)) return false;
      return true;
    });
    preds.forEach(p => {
      if (!seen[p.customerPhone]) {
        seen[p.customerPhone] = { name: p.customerName, phone: p.customerPhone, billNumber: p.billNumber, outlet: p.outlet || '—', count: 0 };
      }
      seen[p.customerPhone].count++;
    });
    return Object.values(seen).sort((a, b) => a.name.localeCompare(b.name));
  }, [prizeType, scope, scopeMatchIds, ctx.livePredictions]);

  /* ── phones already confirmed as winners for this scope ── */
  const confirmedPhonesForScope = useMemo(() => {
    const scopeK = prizeType === 'campaign' ? 'campaign' : scope;
    return new Set(finalWinners.filter(w => w.scope_key === scopeK && w.prize_type === prizeType).map(w => w.winner_phone));
  }, [finalWinners, prizeType, scope]);

  /* ── eligible pool (exclude already-confirmed winners) ── */
  const eligiblePool = useMemo(() => pool.filter(p => !confirmedPhonesForScope.has(p.phone)), [pool, confirmedPhonesForScope]);

  /* ── filtered pool for display ── */
  const displayPool = useMemo(() => {
    const q = searchQ.toLowerCase();
    return pool.filter(p => !q || p.name.toLowerCase().includes(q) || p.phone.includes(q) || p.billNumber.toLowerCase().includes(q));
  }, [pool, searchQ]);

  /* ── slots state ── */
  const ptConfig = PRIZE_TYPES.find(t => t.key === prizeType);
  const scopeK = prizeType === 'campaign' ? 'campaign' : scope;
  const slotsFilled = finalWinners.filter(w => w.prize_type === prizeType && w.scope_key === scopeK).length;
  const nextSlot    = slotsFilled + 1;
  const allSlotsFilled = slotsFilled >= ptConfig.slots;

  /* ── run draw ── */
  function runDraw() {
    if (!eligiblePool.length || allSlotsFilled) return;
    setRolling(true);
    setCandidate(null);
    setRollTick(t => t + 1);
    setTimeout(() => {
      const winner = eligiblePool[Math.floor(Math.random() * eligiblePool.length)];
      setCandidate(winner);
      setRolling(false);
    }, 1800);
  }

  /* ── confirm winner ── */
  async function confirmWinner() {
    if (!candidate || savingWinner) return;
    setSavingWinner(true);
    const scopeLabel = prizeType === 'campaign'
      ? 'Full Campaign 2026'
      : prizeType === 'matchday'
        ? (matchdayOptions.find(o => o.value === scope)?.label || scope)
        : (weekOptions.find(o => o.value === scope)?.label || scope);
    const prizeLabel = prizeType === 'campaign'
      ? 'Grand Prize'
      : prizeType === 'weekly'
        ? `${scopeLabel} · Winner`
        : `${scopeLabel} · Prize ${nextSlot} of ${ptConfig.slots}`;
    try {
      const r = await fetch('/api/draw-winners', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-admin-key': ctx.adminToken },
        body: JSON.stringify({
          prizeType, prizeLabel, scopeKey: scopeK, scopeLabel,
          winnerName: candidate.name, winnerPhone: candidate.phone,
          billNumber: candidate.billNumber, poolSize: eligiblePool.length,
        }),
      });
      if (!r.ok) throw new Error(await r.text());
      const saved = await r.json();
      setFinalWinners(prev => [saved, ...prev]);
      setCandidate(null);
      ctx.setToast({ message: `Winner confirmed: ${candidate.name}`, tone: 'success' });
    } catch (e) {
      ctx.setToast({ message: `Save failed: ${e.message}`, tone: 'error' });
    } finally { setSavingWinner(false); }
  }


  const ptColor = ptConfig.color;

  return (
    <AdminSection title="Lucky Draw" sub="Run official prize draws. Results are saved to the database once confirmed.">

      {/* ── Prize type tabs ── */}
      <div style={{ display: 'flex', gap: 0, marginBottom: 20, borderBottom: '2px solid var(--grey-200)' }}>
        {PRIZE_TYPES.map(pt => (
          <button key={pt.key} onClick={() => setPrizeType(pt.key)} style={{
            padding: '10px 22px', border: 'none', background: 'none', cursor: 'pointer',
            fontFamily: 'inherit', fontSize: 14, fontWeight: 600,
            color: prizeType === pt.key ? pt.color : 'var(--grey-500)',
            borderBottom: `3px solid ${prizeType === pt.key ? pt.color : 'transparent'}`,
            marginBottom: -2, transition: 'color 0.15s',
          }}>
            {pt.label}
            <span style={{ marginLeft: 7, fontSize: 11, fontWeight: 400, color: prizeType === pt.key ? pt.color : 'var(--grey-400)' }}>
              ×{pt.slots}
            </span>
          </button>
        ))}
      </div>
      <div style={{ fontSize: 12.5, color: 'var(--grey-500)', marginBottom: 18, marginTop: -12 }}>{ptConfig.sub}</div>

      {/* ── Scope selector ── */}
      {prizeType !== 'campaign' && (
        <div style={{ marginBottom: 20, maxWidth: 440 }}>
          <FormLabel>{prizeType === 'matchday' ? 'Select Match Day' : 'Select Week'}</FormLabel>
          <select value={scope} onChange={e => { setScope(e.target.value); setCandidate(null); }} style={inputStyle}>
            <option value="">— choose {prizeType === 'matchday' ? 'a match day' : 'a week'} —</option>
            {(prizeType === 'matchday' ? matchdayOptions : weekOptions).map(o => (
              <option key={o.value} value={o.value}>{o.label}</option>
            ))}
          </select>
        </div>
      )}

      {/* ── Main draw area (only when scope is set) ── */}
      {(prizeType === 'campaign' || scope) && (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 360px', gap: 18, alignItems: 'start' }} className="draw-main-grid">

          {/* Pool panel */}
          <Panel title={`Draw pool · ${pool.length} participant${pool.length !== 1 ? 's' : ''}`} padding={0}>
            <div style={{ padding: '10px 14px', borderBottom: '1px solid var(--grey-100)' }}>
              <input
                value={searchQ}
                onChange={e => setSearchQ(e.target.value)}
                placeholder="Search name, phone or bill..."
                style={{ ...inputStyle, margin: 0 }}
              />
            </div>
            {pool.length === 0 ? (
              <div style={{ padding: 24, textAlign: 'center', color: 'var(--grey-500)', fontSize: 13 }}>
                No participants in this pool yet.
              </div>
            ) : (
              <div style={{ maxHeight: 360, overflowY: 'auto' }}>
                {displayPool.length === 0 ? (
                  <div style={{ padding: 16, color: 'var(--grey-400)', fontSize: 13 }}>No match for "{searchQ}".</div>
                ) : displayPool.map(p => {
                  const isWinner = confirmedPhonesForScope.has(p.phone);
                  return (
                    <div key={p.phone} style={{
                      padding: '9px 14px', borderBottom: '1px solid var(--grey-50)',
                      display: 'flex', alignItems: 'center', gap: 10,
                      background: isWinner ? '#f0fdf4' : candidate?.phone === p.phone ? '#fff7ed' : undefined,
                      opacity: isWinner ? 0.5 : 1,
                    }}>
                      <div style={{
                        width: 32, height: 32, borderRadius: '50%', flexShrink: 0,
                        background: isWinner ? '#16a34a' : ptColor, color: '#fff',
                        display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 13, fontWeight: 700,
                      }}>
                        {isWinner ? '✓' : p.name[0]?.toUpperCase()}
                      </div>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontWeight: 600, fontSize: 13, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.name}</div>
                        <div style={{ fontSize: 11.5, color: 'var(--grey-500)', fontFamily: "'JetBrains Mono',monospace" }}>{p.phone} · {p.billNumber}</div>
                      </div>
                      <div style={{ fontSize: 11, color: 'var(--grey-400)', textAlign: 'right', flexShrink: 0 }}>
                        {p.count} pred{p.count !== 1 ? 's' : ''}
                        {isWinner && <div style={{ color: '#16a34a', fontWeight: 700 }}>WINNER</div>}
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </Panel>

          {/* Draw engine panel */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>

            {/* Slot indicator */}
            <div style={{ display: 'flex', gap: 8 }}>
              {Array.from({ length: ptConfig.slots }).map((_, i) => {
                const filled = i < slotsFilled;
                const active = i === slotsFilled;
                return (
                  <div key={i} style={{
                    flex: 1, padding: '8px 12px', border: `2px solid ${filled ? '#16a34a' : active ? ptColor : 'var(--grey-200)'}`,
                    background: filled ? '#f0fdf4' : active ? `${ptColor}11` : '#fff',
                    textAlign: 'center', fontSize: 12, fontWeight: 700,
                    color: filled ? '#16a34a' : active ? ptColor : 'var(--grey-400)',
                  }}>
                    {filled ? '✓ Confirmed' : active ? `Prize ${i + 1}` : `Prize ${i + 1}`}
                  </div>
                );
              })}
            </div>

            {/* Winner card / draw prompt */}
            <div style={{
              minHeight: 180, border: `2px dashed ${allSlotsFilled ? '#16a34a' : ptColor}`,
              background: allSlotsFilled ? '#f0fdf4' : '#fff',
              display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
              padding: 20, textAlign: 'center', gap: 10,
            }}>
              {allSlotsFilled ? (
                <>
                  <div style={{ fontSize: 28 }}>🏆</div>
                  <div style={{ fontWeight: 700, color: '#16a34a', fontSize: 15 }}>All prizes drawn!</div>
                  <div style={{ fontSize: 12.5, color: 'var(--grey-500)' }}>See winners list below.</div>
                </>
              ) : rolling ? (
                <>
                  <div style={{ fontSize: 32, animation: 'spin 0.4s linear infinite' }}>🎲</div>
                  <div style={{ fontWeight: 700, color: ptColor, fontSize: 14 }}>Drawing...</div>
                  <div style={{ fontSize: 12, color: 'var(--grey-500)' }}>Selecting from {eligiblePool.length} eligible participants</div>
                </>
              ) : candidate ? (
                <>
                  <div style={{ fontSize: 28 }}>🎉</div>
                  <div style={{ fontSize: 11, letterSpacing: '0.15em', textTransform: 'uppercase', color: ptColor, fontWeight: 700, marginBottom: 2 }}>
                    Prize {nextSlot} of {ptConfig.slots}
                  </div>
                  <div style={{ fontWeight: 700, fontSize: 20, lineHeight: 1.2 }}>{candidate.name}</div>
                  <div style={{ fontFamily: "'JetBrains Mono',monospace", fontSize: 13, color: 'var(--grey-600)' }}>{candidate.phone}</div>
                  <div style={{ fontFamily: "'JetBrains Mono',monospace", fontSize: 12, color: 'var(--grey-500)' }}>Bill: {candidate.billNumber} · {candidate.outlet}</div>
                  <div style={{ fontSize: 11.5, color: 'var(--grey-400)', marginTop: 2 }}>from pool of {eligiblePool.length}</div>
                </>
              ) : (
                <>
                  <div style={{ fontSize: 28 }}>🎯</div>
                  <div style={{ fontWeight: 600, color: 'var(--grey-500)', fontSize: 14 }}>
                    {pool.length === 0 ? 'No participants yet' : `${eligiblePool.length} eligible · Click to draw`}
                  </div>
                </>
              )}
            </div>

            {/* Action buttons */}
            {!allSlotsFilled && (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {!candidate ? (
                  <AdminBtn kind="primary" icon="trophy" disabled={rolling || eligiblePool.length === 0} onClick={runDraw}
                    style={{ background: ptColor, border: 'none' }}>
                    {rolling ? 'Drawing…' : `🎲 Run Draw${ptConfig.slots > 1 ? ` (Prize ${nextSlot} of ${ptConfig.slots})` : ''}`}
                  </AdminBtn>
                ) : (
                  <>
                    <AdminBtn kind="primary" icon="check" disabled={savingWinner} onClick={confirmWinner}
                      style={{ background: '#16a34a', border: 'none' }}>
                      {savingWinner ? 'Saving…' : '✓ Confirm Winner'}
                    </AdminBtn>
                    <AdminBtn kind="ghost" icon="bolt" disabled={savingWinner} onClick={() => setCandidate(null)}>
                      ↺ Re-draw
                    </AdminBtn>
                  </>
                )}
              </div>
            )}
          </div>
        </div>
      )}

      {/* ── Finalized winners list ── */}
      <div style={{ marginTop: 32 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
          <div className="font-display" style={{ fontSize: 17 }}>Confirmed Winners</div>
          {finalWinners.length > 0 && (
            <AdminBtn kind="outline" icon="receipt" onClick={() => {
              const rows = finalWinners.map((w, i) => ({
                '#': i + 1, 'Prize Type': w.prize_type, 'Prize': w.prize_label,
                'Scope': w.scope_label, 'Winner': w.winner_name, 'Phone': w.winner_phone,
                'Bill': w.bill_number, 'Pool Size': w.pool_size,
                'Date': new Date(w.finalized_at).toLocaleDateString(),
              }));
              exportRowsToXlsx(`draw_winners_${Date.now()}.xlsx`, 'Draw Winners', rows);
              ctx.setToast({ message: `Exported ${finalWinners.length} winners.`, tone: 'success' });
            }}>Export XLSX</AdminBtn>
          )}
        </div>

        {loadingFinal ? (
          <div style={{ color: 'var(--grey-400)', fontSize: 13 }}>Loading…</div>
        ) : finalWinners.length === 0 ? (
          <div style={{ color: 'var(--grey-400)', fontSize: 13, padding: '20px 0' }}>No confirmed winners yet. Run a draw above to get started.</div>
        ) : (
          <div style={{ overflowX: 'auto' }}>
            <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 680 }}>
              <thead>
                <tr style={{ background: 'var(--grey-50)' }}>
                  <Th>#</Th><Th>Prize</Th><Th>Scope</Th><Th>Winner</Th><Th>Phone</Th><Th>Bill</Th><Th align="right">Pool</Th><Th>Date</Th>
                </tr>
              </thead>
              <tbody>
                {finalWinners.map((w, i) => {
                  const pt = PRIZE_TYPES.find(t => t.key === w.prize_type);
                  return (
                    <tr key={w.id} style={{ borderTop: '1px solid var(--grey-100)' }}>
                      <Td><span className="font-display" style={{ fontSize: 15, color: pt?.color || 'var(--orange)' }}>{String(i + 1).padStart(2, '0')}</span></Td>
                      <Td>
                        <span style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: pt?.color }}>{pt?.label}</span>
                        <div style={{ fontSize: 12, color: 'var(--grey-500)', marginTop: 1 }}>{w.prize_label}</div>
                      </Td>
                      <Td><span style={{ fontSize: 12.5 }}>{w.scope_label}</span></Td>
                      <Td><strong>{w.winner_name}</strong></Td>
                      <Td><span className="font-mono" style={{ fontSize: 12.5 }}>{w.winner_phone}</span></Td>
                      <Td><span className="font-mono" style={{ fontSize: 12.5 }}>{w.bill_number}</span></Td>
                      <Td align="right"><span className="font-mono" style={{ fontSize: 12 }}>{w.pool_size}</span></Td>
                      <Td><span style={{ fontSize: 12, color: 'var(--grey-500)' }}>{new Date(w.finalized_at).toLocaleDateString()}</span></Td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </div>

      <style>{`
        @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
        @media (max-width: 820px) {
          .draw-main-grid { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </AdminSection>
  );
}

/* ============================================================
   FLAG UPLOAD
   ============================================================ */
function AdminFlags({ ctx }) {
  // customFlags: { flagCode: url } from Supabase
  const [customFlags, setCustomFlags] = useState({});
  const [loadingFlags, setLoadingFlags] = useState(true);

  // Upload modal state
  const [activeCode, setActiveCode] = useState(null);  // FIFA flag code being uploaded
  const [activeName, setActiveName] = useState('');
  const [preview,    setPreview]    = useState(null);
  const [busy,       setBusy]       = useState(false);
  const [deleting,   setDeleting]   = useState(null);
  const [msg,        setMsg]        = useState(null);
  const fileRef = React.useRef();

  // Build ordered team list: [{teamKey, flagCode, name}]
  // Uses t.flag as the upload code (not team key) -- fixes SAF->RSA mismatch
  const teams = React.useMemo(() => {
    return Object.entries(TEAMS)
      .map(([k, t]) => ({ teamKey: k, flagCode: t.flag || k, name: t.name }))
      .sort((a, b) => a.name.localeCompare(b.name));
  }, []);

  function loadFlags() {
    setLoadingFlags(true);
    fetch('/api/flags')
      .then(r => r.ok ? r.json() : {})
      .then(data => setCustomFlags(data || {}))
      .catch(() => {})
      .finally(() => setLoadingFlags(false));
  }

  useEffect(() => { loadFlags(); }, []);

  function openUpload(flagCode, name) {
    setActiveCode(flagCode);
    setActiveName(name);
    setPreview(null);
    setMsg(null);
    if (fileRef.current) fileRef.current.value = '';
  }

  function closeUpload() {
    setActiveCode(null);
    setPreview(null);
    setMsg(null);
  }

  function onFile(e) {
    const file = e.target.files[0];
    if (!file) return;
    setMsg(null);
    const reader = new FileReader();
    reader.onload = function(ev) {
      const img = new Image();
      img.onload = function() {
        const canvas = document.createElement('canvas');
        canvas.width = 320; canvas.height = 213;
        const c = canvas.getContext('2d');
        const srcRatio = img.width / img.height;
        const dstRatio = 320 / 213;
        let sx = 0, sy = 0, sw = img.width, sh = img.height;
        if (srcRatio > dstRatio) { sw = img.height * dstRatio; sx = (img.width - sw) / 2; }
        else { sh = img.width / dstRatio; sy = (img.height - sh) / 2; }
        c.drawImage(img, sx, sy, sw, sh, 0, 0, 320, 213);
        setPreview(canvas.toDataURL('image/png'));
      };
      img.src = ev.target.result;
    };
    reader.readAsDataURL(file);
  }

  async function upload() {
    if (!preview || !activeCode) return;
    setBusy(true); setMsg(null);
    try {
      const res = await fetch('/api/flags', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-admin-key': ctx.adminToken },
        body: JSON.stringify({ code: activeCode, imageData: preview }),
      });
      const data = await res.json();
      if (!res.ok) {
        setMsg({ ok: false, text: data.error || 'Upload failed.' });
      } else {
        setMsg({ ok: true, text: activeCode + ' uploaded.' });
        loadFlags();
        setTimeout(closeUpload, 1200);
      }
    } catch(_) {
      setMsg({ ok: false, text: 'Network error.' });
    }
    setBusy(false);
  }

  async function deleteFlag(flagCode) {
    if (!window.confirm('Remove custom flag for ' + flagCode + '? Reverts to CDN default.')) return;
    setDeleting(flagCode);
    try {
      const res = await fetch('/api/flags?code=' + encodeURIComponent(flagCode), {
        method: 'DELETE',
        headers: { 'x-admin-key': ctx.adminToken },
      });
      if (res.ok) {
        loadFlags();
        ctx.setToast && ctx.setToast({ message: flagCode + ' custom flag removed.', tone: 'success' });
      } else {
        const d = await res.json().catch(() => ({}));
        ctx.setToast && ctx.setToast({ message: d.error || 'Delete failed.', tone: 'error' });
      }
    } catch(_) {
      ctx.setToast && ctx.setToast({ message: 'Network error.', tone: 'error' });
    }
    setDeleting(null);
  }

  const customCount = Object.keys(customFlags).length;

  return (
    <AdminSection
      title="Flag Images"
      sub={'Custom uploads override the CDN flag for any team. ' + customCount + ' custom flag' + (customCount !== 1 ? 's' : '') + ' active.'}
    >
      {/* Upload modal overlay */}
      {activeCode && (
        <div style={{
          position: 'fixed', inset: 0, zIndex: 60,
          background: 'rgba(17,6,24,0.55)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          padding: 20,
        }} onClick={closeUpload}>
          <div style={{
            background: '#fff', borderRadius: 12, padding: 28, width: '100%', maxWidth: 480,
            boxShadow: '0 24px 64px rgba(17,6,24,0.30)',
          }} onClick={e => e.stopPropagation()}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20 }}>
              <div>
                <div className="font-display" style={{ fontSize: 20, letterSpacing: '-0.01em' }}>
                  Upload flag for {activeName}
                </div>
                <div style={{ fontSize: 12, color: 'var(--grey-500)', marginTop: 3 }}>
                  Code: {activeCode} -- auto-resized to 320x213 PNG (3:2)
                </div>
              </div>
              <button onClick={closeUpload} style={{ background: 'none', border: '1.5px solid var(--grey-200)', borderRadius: 6, padding: '6px 10px', cursor: 'pointer', fontSize: 16, color: 'var(--grey-500)' }}>x</button>
            </div>

            {/* Current flag side-by-side */}
            <div style={{ display: 'flex', gap: 20, marginBottom: 20 }}>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 700, color: 'var(--grey-500)', marginBottom: 6 }}>Current</div>
                {customFlags[activeCode] ? (
                  <img src={customFlags[activeCode] + '?v=' + Date.now()} style={{ width: '100%', height: 80, objectFit: 'cover', borderRadius: 6, border: '2px solid var(--orange)' }} alt="current" />
                ) : (
                  <img src={'https://flagcdn.com/' + (window._FIFA_ISO_ADMIN && window._FIFA_ISO_ADMIN[activeCode] ? window._FIFA_ISO_ADMIN[activeCode] : activeCode.toLowerCase()) + '.svg'} style={{ width: '100%', height: 80, objectFit: 'cover', borderRadius: 6, border: '1.5px solid var(--grey-200)' }} alt="cdn" />
                )}
                <div style={{ fontSize: 10, color: customFlags[activeCode] ? 'var(--orange)' : 'var(--grey-400)', textAlign: 'center', marginTop: 4, fontWeight: 600 }}>
                  {customFlags[activeCode] ? 'CUSTOM' : 'CDN DEFAULT'}
                </div>
              </div>
              {preview && (
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 700, color: 'var(--grey-500)', marginBottom: 6 }}>New upload</div>
                  <img src={preview} style={{ width: '100%', height: 80, objectFit: 'cover', borderRadius: 6, border: '2px solid var(--success)' }} alt="new" />
                  <div style={{ fontSize: 10, color: 'var(--success)', textAlign: 'center', marginTop: 4, fontWeight: 600 }}>READY TO UPLOAD</div>
                </div>
              )}
            </div>

            {/* File picker */}
            <input
              ref={fileRef}
              type="file"
              accept="image/*"
              onChange={onFile}
              style={{
                display: 'block', width: '100%', padding: '10px 12px',
                border: '1.5px solid var(--grey-200)', borderRadius: 6,
                fontSize: 13, cursor: 'pointer', background: 'var(--grey-50)',
                marginBottom: 14,
              }}
            />

            {msg && (
              <div style={{
                padding: '10px 14px', borderRadius: 6, fontSize: 13, fontWeight: 500, marginBottom: 14,
                background: msg.ok ? '#f0fdf4' : '#fef2f2',
                color: msg.ok ? 'var(--success)' : '#dc2626',
                border: '1px solid ' + (msg.ok ? '#bbf7d0' : '#fecaca'),
              }}>{msg.text}</div>
            )}

            <div style={{ display: 'flex', gap: 10 }}>
              <AdminBtn kind="primary" icon="upload" onClick={upload} disabled={busy || !preview}>
                {busy ? 'Uploading...' : 'Upload'}
              </AdminBtn>
              <AdminBtn kind="outline" onClick={closeUpload}>Cancel</AdminBtn>
            </div>
          </div>
        </div>
      )}

      {/* All teams grid */}
      <Panel title={'All 48 teams -- click any flag to upload a replacement' + (loadingFlags ? ' (loading...)' : '')}>
        <div style={{
          display: 'grid',
          gridTemplateColumns: 'repeat(auto-fill, minmax(130px, 1fr))',
          gap: 12,
        }}>
          {teams.map(({ teamKey, flagCode, name }) => {
            const hasCustom = !!customFlags[flagCode];
            const iso = window._FIFA_ISO_ADMIN && window._FIFA_ISO_ADMIN[flagCode] ? window._FIFA_ISO_ADMIN[flagCode] : flagCode.toLowerCase();
            const displaySrc = hasCustom
              ? customFlags[flagCode] + '?v=' + Date.now()
              : 'https://flagcdn.com/' + iso + '.svg';
            return (
              <div key={teamKey} style={{ position: 'relative' }}>
                <button
                  onClick={() => openUpload(flagCode, name)}
                  style={{
                    width: '100%', background: 'none', border: '2px solid ' + (hasCustom ? 'var(--orange)' : 'var(--grey-200)'),
                    borderRadius: 8, padding: '10px 8px 8px',
                    cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6,
                    transition: 'border-color 0.15s',
                  }}
                  onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--orange)'; }}
                  onMouseLeave={e => { e.currentTarget.style.borderColor = hasCustom ? 'var(--orange)' : 'var(--grey-200)'; }}
                >
                  <img
                    src={displaySrc}
                    style={{ width: 72, height: 48, objectFit: 'cover', borderRadius: 4, border: '1px solid var(--grey-100)' }}
                    alt={name}
                    onError={e => { e.currentTarget.style.opacity = '0.25'; }}
                  />
                  <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: '0.04em', textAlign: 'center', lineHeight: 1.2 }}>{name}</div>
                  <div style={{ fontSize: 9, letterSpacing: '0.12em', textTransform: 'uppercase', color: hasCustom ? 'var(--orange)' : 'var(--grey-400)', fontWeight: 700 }}>
                    {hasCustom ? 'Custom' : flagCode}
                  </div>
                </button>
                {/* Delete custom flag */}
                {hasCustom && (
                  <button
                    onClick={e => { e.stopPropagation(); deleteFlag(flagCode); }}
                    disabled={deleting === flagCode}
                    title="Remove custom flag"
                    style={{
                      position: 'absolute', top: 4, right: 4,
                      width: 20, height: 20, borderRadius: '50%',
                      background: '#fee2e2', border: '1px solid #fca5a5',
                      color: '#b91c1c', fontSize: 12, fontWeight: 700,
                      cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
                      lineHeight: 1, padding: 0,
                    }}
                  >x</button>
                )}
              </div>
            );
          })}
        </div>
      </Panel>
    </AdminSection>
  );
}

/* ─── Audit Log ─────────────────────────────────────────────────────────── */
function AdminAuditLog({ ctx }) {
  const { adminToken } = ctx;

  const [logs,      setLogs]      = React.useState([]);
  const [loading,   setLoading]   = React.useState(false);
  const [error,     setError]     = React.useState('');
  const [actorType, setActorType] = React.useState('all');
  const [dateFrom,  setDateFrom]  = React.useState('');
  const [dateTo,    setDateTo]    = React.useState('');

  const fetchLogs = React.useCallback(() => {
    setLoading(true);
    const params = new URLSearchParams({ limit: '300' });
    if (actorType !== 'all') params.set('actor_type', actorType);
    if (dateFrom) params.set('date_from', dateFrom + 'T00:00:00Z');
    if (dateTo)   params.set('date_to',   dateTo   + 'T23:59:59Z');

    fetch(`/api/audit-log?${params}`, { headers: { 'x-admin-key': adminToken } })
      .then(r => r.json())
      .then(data => { setLogs(Array.isArray(data) ? data : []); setError(''); })
      .catch(() => setError('Failed to load audit log.'))
      .finally(() => setLoading(false));
  }, [adminToken, actorType, dateFrom, dateTo]);

  React.useEffect(() => { fetchLogs(); }, [fetchLogs]);

  React.useEffect(() => {
    const id = setInterval(fetchLogs, 30000);
    return () => clearInterval(id);
  }, [fetchLogs]);

  const TYPE_COLOR = { user: '#2563eb', admin: 'var(--orange)', system: '#6b7280' };
  const TYPE_LABEL = { user: 'User', admin: 'Admin', system: 'System' };

  const selStyle = {
    padding: '8px 10px', border: '1px solid #3f3f46', borderRadius: 7,
    background: '#18181b', color: '#f4f4f5', fontSize: 13,
  };

  return (
    <AdminSection title="Audit Log" sub="All system activity — read only, newest first.">
      <Panel>
        {/* Filters */}
        <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', marginBottom: 18, alignItems: 'flex-end' }}>
          <div>
            <FormLabel>Actor type</FormLabel>
            <select value={actorType} onChange={e => setActorType(e.target.value)} style={selStyle}>
              <option value="all">All types</option>
              <option value="user">User (public)</option>
              <option value="admin">Admin</option>
              <option value="system">System / Webhook</option>
            </select>
          </div>
          <div>
            <FormLabel>From</FormLabel>
            <input type="date" value={dateFrom} onChange={e => setDateFrom(e.target.value)} style={selStyle} />
          </div>
          <div>
            <FormLabel>To</FormLabel>
            <input type="date" value={dateTo} onChange={e => setDateTo(e.target.value)} style={selStyle} />
          </div>
          <AdminBtn onClick={fetchLogs}>Refresh</AdminBtn>
          {(dateFrom || dateTo || actorType !== 'all') && (
            <AdminBtn kind="ghost" onClick={() => { setActorType('all'); setDateFrom(''); setDateTo(''); }}>
              Clear filters
            </AdminBtn>
          )}
        </div>

        {error && <p style={{ color: '#f87171', marginBottom: 12, fontSize: 13 }}>{error}</p>}
        {loading && logs.length === 0 && <p style={{ color: '#a1a1aa', fontSize: 13 }}>Loading…</p>}

        <div style={{ overflowX: 'auto' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
            <thead>
              <tr>
                <Th>Time (MVT)</Th>
                <Th>Type</Th>
                <Th>Actor</Th>
                <Th>Action</Th>
                <Th>Entity</Th>
                <Th>Detail</Th>
              </tr>
            </thead>
            <tbody>
              {logs.length === 0 && !loading && (
                <tr>
                  <td colSpan={6} style={{ textAlign: 'center', color: '#52525b', padding: '28px 0', fontSize: 13 }}>
                    No log entries found.
                  </td>
                </tr>
              )}
              {logs.map(log => {
                const col = TYPE_COLOR[log.actor_type] || '#6b7280';
                return (
                  <tr key={log.id} style={{ borderBottom: '1px solid #27272a' }}>
                    <Td style={{ whiteSpace: 'nowrap', color: '#a1a1aa', fontSize: 11 }}>
                      {new Date(log.created_at).toLocaleString('en-MV', {
                        timeZone: 'Indian/Maldives', hour12: false,
                        year: 'numeric', month: '2-digit', day: '2-digit',
                        hour: '2-digit', minute: '2-digit', second: '2-digit',
                      })}
                    </Td>
                    <Td>
                      <span style={{
                        background: col + '22', color: col,
                        border: `1px solid ${col}55`,
                        borderRadius: 4, padding: '2px 8px',
                        fontSize: 11, fontWeight: 700, whiteSpace: 'nowrap',
                      }}>
                        {TYPE_LABEL[log.actor_type] || log.actor_type}
                      </span>
                    </Td>
                    <Td style={{ maxWidth: 150, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                      {log.actor_name
                        ? <><span style={{ color: '#f4f4f5' }}>{log.actor_name}</span>
                            {log.actor_id && log.actor_id !== log.actor_name
                              ? <span style={{ color: '#71717a', marginLeft: 4, fontSize: 11 }}>{log.actor_id}</span>
                              : null}
                          </>
                        : <span style={{ color: '#71717a' }}>{log.actor_id || '—'}</span>
                      }
                    </Td>
                    <Td>
                      <span style={{ fontFamily: 'monospace', color: '#fbbf24', fontWeight: 600, fontSize: 12 }}>
                        {log.action}
                      </span>
                    </Td>
                    <Td style={{ color: '#a1a1aa', fontSize: 11, whiteSpace: 'nowrap' }}>
                      {[log.entity_type, log.entity_id].filter(Boolean).join(' · ') || '—'}
                    </Td>
                    <Td style={{ maxWidth: 260, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: '#52525b', fontSize: 11 }}
                      title={log.detail ? JSON.stringify(log.detail, null, 2) : ''}>
                      {log.detail ? JSON.stringify(log.detail) : '—'}
                    </Td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>

        {logs.length > 0 && (
          <p style={{ color: '#52525b', fontSize: 12, marginTop: 10, textAlign: 'right' }}>
            {logs.length} entries · auto-refreshes every 30 s
          </p>
        )}
      </Panel>
    </AdminSection>
  );
}

Object.assign(window, {
  AdminOverview, AdminMatches, AdminCreate, AdminSettle, AdminDraw, AdminFlags,
  AdminAuditLog,
  Th, Td, IconBtn, FormLabel, FormSelect, StatCard,
});
