/* Admin data + content + settings views. */

/* ============================================================
   PREDICTIONS BROWSER (PII visible to admin only)
   ============================================================ */
function AdminPredictions({ ctx }) {
  const [q, setQ] = useState('');
  const [matchFilter, setMatchFilter] = useState('');
  const [matchdayFilter, setMatchdayFilter] = useState('');
  const [outletFilter, setOutletFilter] = useState('');
  const [correctFilter, setCorrectFilter] = useState(''); // '', 'yes', 'no', 'pending'
  const [page, setPage] = useState(0);
  const pageSize = 12;

  const allPredictions = ctx.livePredictions;
  const loading = ctx.predictionsLoading;
  const loadError = ctx.predictionsError;

  // Group fixtures by kickoff calendar date (Maldives time) into "Matchday N" buckets
  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 * 60 * 60 * 1000);
      const key = mvt.toISOString().slice(0, 10);
      (byDate[key] || (byDate[key] = [])).push(m.id);
    });
    return Object.keys(byDate).sort().map((key, i) => {
      const mvt = new Date(`${key}T00:00:00Z`);
      return {
        value: key,
        label: `Matchday ${i + 1} · ${days[mvt.getUTCDay()]} ${mvt.getUTCDate()} ${months[mvt.getUTCMonth()]}`,
        matchIds: byDate[key],
      };
    });
  }, [ctx.matchesState]);

  const matchdayByMatchId = useMemo(() => {
    const map = {};
    matchdayOptions.forEach(opt => opt.matchIds.forEach(id => { map[id] = opt.value; }));
    return map;
  }, [matchdayOptions]);

  const matchdayLabelByMatchId = useMemo(() => {
    const map = {};
    matchdayOptions.forEach((opt, i) => opt.matchIds.forEach(id => { map[id] = `Matchday ${i + 1}`; }));
    return map;
  }, [matchdayOptions]);

  const filtered = useMemo(() => {
    return allPredictions.filter(p => {
      if (q) {
        const Q = q.toLowerCase();
        if (!(p.customerName + ' ' + p.customerPhone + ' ' + p.billNumber).toLowerCase().includes(Q)) return false;
      }
      if (matchFilter && String(p.matchId) !== matchFilter) return false;
      if (matchdayFilter && matchdayByMatchId[p.matchId] !== matchdayFilter) return false;
      if (outletFilter && p.outlet !== outletFilter) return false;
      if (correctFilter === 'yes' && p.isCorrect !== true) return false;
      if (correctFilter === 'no' && p.isCorrect !== false) return false;
      if (correctFilter === 'pending' && p.isCorrect !== null) return false;
      return true;
    });
  }, [allPredictions, q, matchFilter, matchdayFilter, matchdayByMatchId, outletFilter, correctFilter]);

  const pages = Math.max(1, Math.ceil(filtered.length / pageSize));
  const visible = filtered.slice(page * pageSize, (page + 1) * pageSize);

  return (
    <AdminSection
      title="Predictions"
      sub="Customer data only visible here. Audit, search, filter, and export."
      right={
        <AdminBtn kind="outline" icon="receipt" onClick={() => {
          const rows = filtered.map(p => ({
            'Customer Name': p.customerName,
            'Mobile': p.customerPhone,
            'Outlet': p.outlet || '',
            'Bill Number': p.billNumber,
            'Amount (MVR)': p.amountMyr != null ? Number(p.amountMyr) : '',
            'Match': p.matchLabel,
            'Match Day': matchdayLabelByMatchId[p.matchId] || '',
            'Pick': p.pick,
            'Result': p.isCorrect === true ? 'Correct' : p.isCorrect === false ? 'Incorrect' : 'Pending',
            'Submitted At': new Date(p.submittedAt).toISOString(),
          }));
          exportRowsToXlsx(`predictions_${Date.now()}.xlsx`, 'Predictions', rows);
          ctx.setToast({ message: `Exported ${filtered.length} predictions to XLSX.`, tone: 'success' });
        }}>
          Export {filtered.length} rows
        </AdminBtn>
      }
    >
      <div style={{
        background: '#fff8f3', border: '1.5px solid var(--orange-100)',
        padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14,
        fontSize: 12.5, color: 'var(--ink)',
      }}>
        <span style={{ width: 8, height: 8, background: 'var(--orange)', flexShrink: 0 }} />
        <span>This screen displays personal customer data (name, mobile, bill). It is never reachable from a public endpoint.</span>
      </div>

      {loading && !loadError && (
        <div style={{ padding: '20px 0', color: 'var(--grey-500)', fontSize: 13.5 }}>
          Loading predictions…
        </div>
      )}
      {loadError && (
        <div style={{
          padding: '10px 14px', background: '#fee2e2', color: '#b91c1c',
          border: '1px solid #fecaca', fontSize: 13, marginBottom: 12,
        }}>
          ⚠ {loadError}
          <span style={{ display: 'block', marginTop: 4, fontSize: 12, color: '#7f1d1d' }}>
            Check SUPABASE_URL / SUPABASE_SERVICE_KEY in Vercel env vars.
          </span>
        </div>
      )}

      <Panel padding={0}>
        {/* Filters */}
        <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--grey-200)', display: 'grid', gridTemplateColumns: 'minmax(180px, 1fr) repeat(4, minmax(130px, 200px))', gap: 12, alignItems: 'end' }} className="pred-filters">
          <div>
            <FormLabel>Search</FormLabel>
            <input value={q} onChange={(e) => { setQ(e.target.value); setPage(0); }} placeholder="Name, phone, bill…" style={inputStyle} />
          </div>
          <div>
            <FormLabel>Match</FormLabel>
            <select value={matchFilter} onChange={(e) => { setMatchFilter(e.target.value); setPage(0); }} style={inputStyle}>
              <option value="">All matches</option>
              {ctx.matchesState.map(m => <option key={m.id} value={m.id}>{m.teamA.name} vs {m.teamB.name}</option>)}
            </select>
          </div>
          <div>
            <FormLabel>Matchday</FormLabel>
            <select value={matchdayFilter} onChange={(e) => { setMatchdayFilter(e.target.value); setPage(0); }} style={inputStyle}>
              <option value="">All matchdays</option>
              {matchdayOptions.map(opt => <option key={opt.value} value={opt.value}>{opt.label}</option>)}
            </select>
          </div>
          <div>
            <FormLabel>Outlet</FormLabel>
            <select value={outletFilter} onChange={(e) => { setOutletFilter(e.target.value); setPage(0); }} style={inputStyle}>
              <option value="">All outlets</option>
              {ctx.outletsState.map(o => <option key={o.id} value={o.name}>{o.name}</option>)}
            </select>
          </div>
          <div>
            <FormLabel>Result</FormLabel>
            <select value={correctFilter} onChange={(e) => { setCorrectFilter(e.target.value); setPage(0); }} style={inputStyle}>
              <option value="">All</option>
              <option value="yes">Correct</option>
              <option value="no">Incorrect</option>
              <option value="pending">Pending</option>
            </select>
          </div>
        </div>

        {/* Table */}
        <div style={{ overflowX: 'auto' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 1080 }}>
            <thead>
              <tr style={{ background: 'var(--grey-50)' }}>
                <Th>Customer</Th>
                <Th>Mobile</Th>
                <Th>Bill #</Th>
                <Th>Amount (MVR)</Th>
                <Th>Match · pick</Th>
                <Th>Match Day</Th>
                <Th>Result</Th>
                <Th align="right">Submitted</Th>
              </tr>
            </thead>
            <tbody>
              {visible.map(p => (
                <tr key={p.id} style={{ borderTop: '1px solid var(--grey-100)' }}>
                  <Td>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                      <div style={{
                        width: 28, height: 28, borderRadius: '50%',
                        background: 'var(--ink)', color: 'var(--orange)',
                        display: 'flex', alignItems: 'center', justifyContent: 'center',
                        fontSize: 11, fontWeight: 800, fontFamily: "'Archivo Black', sans-serif",
                      }}>
                        {p.customerName.slice(0, 1)}
                      </div>
                      <span style={{ fontWeight: 600, fontSize: 13.5 }}>{p.customerName}</span>
                    </div>
                  </Td>
                  <Td><span className="font-mono" style={{ fontSize: 12.5 }}>{p.customerPhone}</span></Td>
                  <Td><span className="font-mono" style={{ fontSize: 12.5 }}>{p.billNumber}</span></Td>
                  <Td><span className="font-mono" style={{ fontSize: 13, fontWeight: 700 }}>{p.amountMyr != null ? `MVR ${Number(p.amountMyr).toFixed(2)}` : '—'}</span></Td>
                  <Td>
                    <div style={{ fontSize: 12.5 }}>{p.matchLabel}</div>
                    <div style={{ fontSize: 11, color: 'var(--orange)', fontWeight: 700, letterSpacing: '0.04em', marginTop: 2 }}>
                      → {p.pick.toUpperCase()}
                    </div>
                  </Td>
                  <Td>
                    <span style={{ fontSize: 12.5, color: 'var(--grey-600)' }}>{matchdayLabelByMatchId[p.matchId] || '—'}</span>
                  </Td>
                  <Td>
                    {p.isCorrect === true && <ResultPill tone="green">Correct</ResultPill>}
                    {p.isCorrect === false && <ResultPill tone="grey">Incorrect</ResultPill>}
                    {p.isCorrect === null && <ResultPill tone="ink">Pending</ResultPill>}
                  </Td>
                  <Td align="right">
                    <span style={{ fontSize: 12.5, color: 'var(--grey-600)' }}>{timeAgo(p.submittedAt)}</span>
                  </Td>
                </tr>
              ))}
              {visible.length === 0 && (
                <tr><td colSpan="8" style={{ padding: 32, textAlign: 'center', color: 'var(--grey-500)' }}>No predictions match those filters.</td></tr>
              )}
            </tbody>
          </table>
        </div>

        {/* Pagination */}
        <div style={{
          padding: '12px 18px', borderTop: '1px solid var(--grey-200)',
          display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 10,
        }}>
          <div style={{ fontSize: 12.5, color: 'var(--grey-600)' }}>
            Showing {filtered.length === 0 ? 0 : page * pageSize + 1}–{Math.min((page + 1) * pageSize, filtered.length)} of {filtered.length}
          </div>
          <div style={{ display: 'flex', gap: 6 }}>
            <AdminBtn kind="ghost" disabled={page === 0} onClick={() => setPage(p => p - 1)}>← Prev</AdminBtn>
            <div style={{ display: 'flex', alignItems: 'center', padding: '0 10px', fontSize: 12.5, color: 'var(--grey-700)' }}>
              Page {page + 1} / {pages}
            </div>
            <AdminBtn kind="ghost" disabled={page + 1 >= pages} onClick={() => setPage(p => p + 1)}>Next →</AdminBtn>
          </div>
        </div>
      </Panel>

      <style>{`
        @media (max-width: 900px) {
          .pred-filters { grid-template-columns: 1fr 1fr 1fr !important; }
        }
        @media (max-width: 680px) {
          .pred-filters { grid-template-columns: 1fr 1fr !important; }
        }
        @media (max-width: 540px) {
          .pred-filters { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </AdminSection>
  );
}

function ResultPill({ tone, children }) {
  const palette = {
    green: { bg: 'var(--success-bg)', fg: '#0f5f2e', bd: 'var(--success)' },
    grey:  { bg: 'var(--grey-100)',   fg: 'var(--grey-700)', bd: 'var(--grey-300)' },
    ink:   { bg: 'var(--ink)',        fg: '#fff',            bd: 'var(--ink)' },
  }[tone];
  return (
    <span style={{
      display: 'inline-block', background: palette.bg, color: palette.fg,
      border: `1px solid ${palette.bd}`, padding: '3px 9px',
      fontSize: 10.5, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase',
    }}>{children}</span>
  );
}

/* ============================================================
   OUTLETS MANAGER
   ============================================================ */
function AdminOutlets({ ctx }) {
  const [draft, setDraft] = useState({ id: null, name: '', code: '', address: '' });
  const [outletStats, setOutletStats] = useState(null);
  const [billEntriesByOutlet, setBillEntriesByOutlet] = useState({});
  const [statsError, setStatsError] = useState('');

  useEffect(() => {
    let active = true;
    fetch('/api/get-bill-data', { headers: { 'x-admin-key': ctx.adminToken } })
      .then(r => r.json())
      .then(d => {
        if (!active) return;
        if (d.outletStats) {
          setOutletStats(d.outletStats);
          setStatsError('');
        } else setStatsError(d.error || 'Could not load bill data.');
        if (d.billEntries) {
          const map = {};
          d.billEntries.forEach(e => { if (e.Shop) map[e.Shop] = (map[e.Shop] || 0) + 1; });
          setBillEntriesByOutlet(map);
        }
      })
      .catch(() => { if (active) setStatsError('Network error while loading bill data.'); });
    return () => { active = false; };
  }, [ctx.adminToken]);

  function startNew() { setDraft({ id: null, name: '', code: '', address: '' }); }
  function startEdit(o) { setDraft({ ...o }); }
  function save() {
    if (!draft.name || !draft.code) return;
    if (draft.id) {
      ctx.setOutletsState(s => s.map(o => o.id === draft.id ? { ...draft } : o));
      ctx.setToast({ message: `Outlet "${draft.name}" updated.`, tone: 'success' });
    } else {
      const id = Math.max(0, ...ctx.outletsState.map(o => o.id)) + 1;
      ctx.setOutletsState(s => [...s, { ...draft, id }]);
      ctx.setToast({ message: `Outlet "${draft.name}" added.`, tone: 'success' });
    }
    startNew();
  }
  function remove(id) {
    if (!confirm('Delete this outlet? Predictions tied to it will keep their reference.')) return;
    ctx.setOutletsState(s => s.filter(o => o.id !== id));
    ctx.setToast({ message: 'Outlet removed.', tone: 'success' });
  }

  return (
    <AdminSection
      title="Outlets"
      sub="The five SunFront outlets (from POS bill data). Prediction counts below are derived from each customer's bill."
      right={<AdminBtn kind="primary" icon="pin" onClick={startNew}>Add new outlet</AdminBtn>}
    >
      <div className="admin-2col" style={{ display: 'grid', gridTemplateColumns: '1fr 360px', gap: 18 }}>
        {/* List */}
        <div style={{ display: 'grid', gap: 14 }}>
          {[...ctx.outletsState].sort((a, b) => {
            const ua = outletStats ? (outletStats.find(s => s.outlet === a.name)?.totalBills || 0) : 0;
            const ub = outletStats ? (outletStats.find(s => s.outlet === b.name)?.totalBills || 0) : 0;
            return ub - ua;
          }).map(o => {
            const predCount  = ctx.livePredictions.filter(p => p.outlet === o.name).length;
            const validBills = billEntriesByOutlet[o.name] || 0;
            const usedBills  = outletStats ? (outletStats.find(s => s.outlet === o.name)?.totalBills || 0) : 0;
            const isOnline   = o.code === 'WS';
            const statStyle  = { textAlign: 'center', minWidth: 64 };
            const labelStyle = { fontSize: 10.5, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--grey-500)', fontWeight: 700, marginTop: 3 };
            const numStyle   = { fontSize: 22, lineHeight: 1 };
            return (
              <div key={o.id} style={{
                background: '#fff', border: '1.5px solid var(--grey-200)',
                padding: '16px 18px',
                display: 'flex', alignItems: 'center', gap: 14, flexWrap: 'wrap',
              }}>
                <div style={{
                  width: 48, height: 48,
                  background: isOnline ? '#7c3aed' : 'var(--orange)',
                  color: '#fff',
                  display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
                }}>
                  <Icon name={isOnline ? 'bolt' : 'pin'} size={22} />
                </div>
                <div style={{ flex: 1, minWidth: 180 }}>
                  <div className="font-display" style={{ fontSize: 18 }}>{o.name}</div>
                  <div style={{ fontSize: 12.5, color: 'var(--grey-600)', marginTop: 2 }}>
                    <span className="font-mono">{o.code}</span> · {o.address}
                  </div>
                </div>
                <div style={{ display: 'flex', gap: 20, alignItems: 'center' }}>
                  <div style={statStyle}>
                    <div className="font-display" style={numStyle}>{validBills.toLocaleString()}</div>
                    <div style={labelStyle}>Valid Bill</div>
                  </div>
                  <div style={statStyle}>
                    <div className="font-display" style={{ ...numStyle, color: usedBills > 0 ? 'var(--success, #16a34a)' : undefined }}>{usedBills.toLocaleString()}</div>
                    <div style={labelStyle}>Used Bill</div>
                  </div>
                  <div style={statStyle}>
                    <div className="font-display" style={numStyle}>{predCount.toLocaleString()}</div>
                    <div style={labelStyle}>Predictions</div>
                  </div>
                </div>
                <div style={{ display: 'flex', gap: 6 }}>
                  <IconBtn icon="message" title="Edit" onClick={() => startEdit(o)} />
                  <IconBtn icon="bolt" title="Delete" tone="danger" onClick={() => remove(o.id)} />
                </div>
              </div>
            );
          })}
        </div>

        {/* Edit form */}
        <Panel title={draft.id ? 'Edit outlet' : 'Add new outlet'}>
          <div style={{ display: 'grid', gap: 14 }}>
            <div>
              <FormLabel>Display name</FormLabel>
              <input value={draft.name} onChange={(e) => setDraft({ ...draft, name: e.target.value })} placeholder="e.g. LIVIN" style={inputStyle} />
            </div>
            <div>
              <FormLabel>Code</FormLabel>
              <input value={draft.code} onChange={(e) => setDraft({ ...draft, code: e.target.value.toUpperCase() })} placeholder="LIVIN" className="font-mono input-upper" style={{ ...inputStyle, fontFamily: "'JetBrains Mono', monospace" }} />
            </div>
            <div>
              <FormLabel>Address</FormLabel>
              <input value={draft.address} onChange={(e) => setDraft({ ...draft, address: e.target.value })} placeholder="Building, street" style={inputStyle} />
            </div>
            <div style={{ display: 'flex', gap: 10 }}>
              <AdminBtn kind="primary" icon="check" onClick={save}>{draft.id ? 'Save changes' : 'Add outlet'}</AdminBtn>
              {draft.id && <AdminBtn kind="ghost" onClick={startNew}>Cancel</AdminBtn>}
            </div>
          </div>
        </Panel>
      </div>

      {/* Bill data by outlet -- derived from bill_usage / bill_entries (Shop) */}
      <div style={{ marginTop: 28 }}>
        <div className="font-display" style={{ fontSize: 16, marginBottom: 10 }}>Bill data by outlet</div>
        {statsError && (
          <div style={{
            padding: '10px 14px', background: '#fee2e2', color: '#b91c1c',
            border: '1px solid #fecaca', fontSize: 13, marginBottom: 12,
          }}>
            ⚠ {statsError}
          </div>
        )}
        {!outletStats && !statsError && (
          <div style={{ padding: '20px 0', color: 'var(--grey-500)', fontSize: 13.5 }}>Loading…</div>
        )}
        {outletStats && (
          <div className="outlet-bill-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 14 }}>
            {outletStats.map(o => (
              <div key={o.outlet} style={{ background: '#fff', border: '1.5px solid var(--grey-200)', padding: '16px 18px' }}>
                <div className="font-display" style={{ fontSize: 15, marginBottom: 12 }}>{o.outlet}</div>
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8 }}>
                  <div>
                    <div className="font-display" style={{ fontSize: 22, lineHeight: 1 }}>{o.totalBills}</div>
                    <div style={{ fontSize: 10, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--grey-500)', fontWeight: 700, marginTop: 4 }}>Bills</div>
                  </div>
                  <div>
                    <div className="font-display" style={{ fontSize: 22, lineHeight: 1, color: 'var(--success)' }}>{o.voted}</div>
                    <div style={{ fontSize: 10, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--grey-500)', fontWeight: 700, marginTop: 4 }}>Voted</div>
                  </div>
                  <div>
                    <div className="font-display" style={{ fontSize: 22, lineHeight: 1, color: 'var(--orange)' }}>{o.notVoted}</div>
                    <div style={{ fontSize: 10, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--grey-500)', fontWeight: 700, marginTop: 4 }}>Not voted</div>
                  </div>
                </div>
              </div>
            ))}
            {outletStats.length === 0 && (
              <div style={{ color: 'var(--grey-500)', fontSize: 13.5 }}>No bill usage rows yet.</div>
            )}
          </div>
        )}
      </div>

      <style>{`
        @media (max-width: 900px) {
          .admin-2col { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </AdminSection>
  );
}

/* ============================================================
   CONTENT EDITOR  (homepage text + images)
   ============================================================ */
function AdminContent({ ctx }) {
  const [draft, setDraft] = useState(() => ({ ...ctx.contentState }));
  const dirty = JSON.stringify(draft) !== JSON.stringify(ctx.contentState);

  const update = (path, value) => {
    const parts = path.split('.');
    setDraft(d => {
      const n = { ...d };
      let cur = n;
      for (let i = 0; i < parts.length - 1; i++) {
        cur[parts[i]] = { ...cur[parts[i]] };
        cur = cur[parts[i]];
      }
      cur[parts[parts.length - 1]] = value;
      return n;
    });
  };

  function save() {
    ctx.setContentState(draft);
    ctx.setToast({ message: 'Site content saved. The public site picks this up on next load.', tone: 'success' });
  }
  function discard() {
    setDraft({ ...ctx.contentState });
    ctx.setToast({ message: 'Changes discarded.', tone: 'info' });
  }
  function resetDefaults() {
    if (!confirm('Reset all content to factory defaults? Your edits will be lost.')) return;
    setDraft({ ...SITE_CONTENT_DEFAULTS });
    ctx.setContentState({ ...SITE_CONTENT_DEFAULTS });
    ctx.setToast({ message: 'Content reset to defaults.', tone: 'info' });
  }

  return (
    <AdminSection
      title="Content & images"
      sub="Edit every word and image on the public site. Changes here update Home, the ticket card, and footer."
      right={
        <div style={{ display: 'flex', gap: 8 }}>
          <AdminBtn kind="ghost" onClick={resetDefaults}>Reset defaults</AdminBtn>
          <AdminBtn kind="primary" icon="check" disabled={!dirty} onClick={save}>Publish changes</AdminBtn>
        </div>
      }
    >
      <div className="admin-2col" style={{ display: 'grid', gridTemplateColumns: '1.1fr 0.9fr', gap: 18 }}>
        {/* Editors */}
        <div style={{ display: 'grid', gap: 14 }}>
          <ContentSection title="Hero headline">
            <FieldRow label="Eyebrow badge"
              value={draft.hero.eyebrow}
              onChange={(v) => update('hero.eyebrow', v)} />
            <FieldRow label="Headline"
              value={draft.hero.headline}
              onChange={(v) => update('hero.headline', v)}
              textarea />
            <FieldRow label="Highlighted phrase"
              value={draft.hero.headlineHighlight}
              onChange={(v) => update('hero.headlineHighlight', v)}
              hint="Must be a substring of the headline — gets the orange marker." />
            <FieldRow label="Sub-headline"
              value={draft.hero.sub}
              onChange={(v) => update('hero.sub', v)}
              textarea />
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
              <FieldRow label="Primary CTA"
                value={draft.hero.ctaPrimary}
                onChange={(v) => update('hero.ctaPrimary', v)} />
              <FieldRow label="Secondary CTA"
                value={draft.hero.ctaSecondary}
                onChange={(v) => update('hero.ctaSecondary', v)} />
            </div>
          </ContentSection>

          <ContentSection title="Ticket card">
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 120px', gap: 10 }}>
              <FieldRow label="Tournament name"
                value={draft.ticket.title}
                onChange={(v) => update('ticket.title', v)} />
              <FieldRow label="Year"
                value={draft.ticket.year}
                onChange={(v) => update('ticket.year', v)} />
            </div>
            <FieldRow label="Region"
              value={draft.ticket.region}
              onChange={(v) => update('ticket.region', v)} />
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
              <FieldRow label="Outlets count"
                value={draft.ticket.outlets}
                onChange={(v) => update('ticket.outlets', v)} />
              <FieldRow label="Matches count"
                value={draft.ticket.matches}
                onChange={(v) => update('ticket.matches', v)} />
            </div>
          </ContentSection>

          <ContentSection title="Logo & images">
            <ImageDropzone label="SunFront logo (replaces /public/sunfront-logo.jpg)" current="placeholder" onPick={() => ctx.setToast({ message: 'In production this writes to /public/sunfront-logo.jpg', tone: 'info' })} />
            <ImageDropzone label="Hero background (optional)" current={null} onPick={() => ctx.setToast({ message: 'Uploaded — saved to /public/hero-bg.jpg', tone: 'info' })} />
          </ContentSection>

          <ContentSection title="Brand chrome">
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
              <FieldRow label="Hotline number"
                value={draft.hotline}
                onChange={(v) => update('hotline', v)} mono />
              <FieldRow label="Region"
                value={draft.hotlineRegion}
                onChange={(v) => update('hotlineRegion', v)} />
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 100px', gap: 10 }}>
              <FieldRow label="Tagline"
                value={draft.tagline}
                onChange={(v) => update('tagline', v)} />
              <FieldRow label="Since"
                value={draft.since}
                onChange={(v) => update('since', v)} mono />
            </div>
            <FieldRow label="Footer links"
              value={draft.footerLinks}
              onChange={(v) => update('footerLinks', v)} mono />
            <FieldRow label="Footer legal"
              value={draft.footerLegal}
              onChange={(v) => update('footerLegal', v)}
              textarea />
          </ContentSection>
        </div>

        {/* Live preview panel */}
        <div style={{ display: 'grid', gap: 14, alignContent: 'start', position: 'sticky', top: 90 }}>
          <Panel title="Live preview" action={<span style={{ fontSize: 11, color: 'var(--grey-500)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>Hero</span>}>
            <ContentPreview draft={draft} />
          </Panel>
          <Panel title="Ticket card preview">
            <TicketPreview draft={draft} />
          </Panel>
        </div>
      </div>

      <style>{`
        @media (max-width: 1100px) {
          .admin-2col { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </AdminSection>
  );
}

function ContentSection({ title, children }) {
  const [open, setOpen] = useState(true);
  return (
    <div style={{ background: '#fff', border: '1.5px solid var(--grey-200)' }}>
      <button onClick={() => setOpen(o => !o)} style={{
        width: '100%', background: open ? 'var(--grey-50)' : '#fff', border: 'none',
        padding: '12px 18px', textAlign: 'left', cursor: 'pointer',
        display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        borderBottom: open ? '1px solid var(--grey-200)' : 'none',
      }}>
        <span className="font-display" style={{ fontSize: 15, letterSpacing: '-0.01em' }}>{title}</span>
        <span style={{ color: 'var(--grey-500)', fontSize: 12, transform: open ? 'rotate(180deg)' : 'rotate(0)', transition: 'transform 0.2s' }}>▼</span>
      </button>
      {open && <div style={{ padding: 18, display: 'grid', gap: 12 }}>{children}</div>}
    </div>
  );
}
function FieldRow({ label, value, onChange, textarea, hint, mono }) {
  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
        <FormLabel>{label}</FormLabel>
        {hint && <span style={{ fontSize: 11, color: 'var(--grey-500)' }}>{hint}</span>}
      </div>
      {textarea ? (
        <textarea value={value} onChange={(e) => onChange(e.target.value)} rows={3} style={{ ...inputStyle, resize: 'vertical', fontFamily: 'inherit' }} />
      ) : (
        <input value={value} onChange={(e) => onChange(e.target.value)}
          className={mono ? 'font-mono' : ''}
          style={{ ...inputStyle, fontFamily: mono ? "'JetBrains Mono', monospace" : 'inherit' }} />
      )}
    </div>
  );
}
function ImageDropzone({ label, current, onPick }) {
  return (
    <div>
      <FormLabel>{label}</FormLabel>
      <div onClick={onPick} style={{
        border: '2px dashed var(--grey-300)', padding: 18, background: 'var(--grey-50)',
        cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 14,
      }}>
        <div style={{
          width: 60, height: 60, background: current ? 'var(--ink)' : 'var(--grey-100)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          {current ? <SunFrontLogo height={26} onWhite={false} /> :
            <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--grey-400)" strokeWidth="2"><rect x="3" y="3" width="18" height="18"/><path d="M3 16l5-5 4 4 3-3 6 6"/><circle cx="9" cy="9" r="2"/></svg>}
        </div>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 13.5, fontWeight: 600 }}>
            {current ? 'Current asset · click to replace' : 'Click or drag a file here'}
          </div>
          <div style={{ fontSize: 11.5, color: 'var(--grey-500)', marginTop: 2 }}>PNG / JPG · recommended ≤ 500 KB</div>
        </div>
        <span style={{
          background: 'var(--orange)', color: '#fff', padding: '7px 12px',
          fontSize: 11, fontWeight: 700, letterSpacing: '0.08em', textTransform: 'uppercase',
        }}>Upload</span>
      </div>
    </div>
  );
}

function ContentPreview({ draft }) {
  const hl = draft.hero.headlineHighlight;
  const parts = hl && draft.hero.headline.includes(hl)
    ? draft.hero.headline.split(hl)
    : [draft.hero.headline];
  return (
    <div style={{ background: '#fff', padding: 6 }}>
      <div className="skew-tag" style={{
        background: 'var(--ink)', color: '#fff', display: 'inline-flex', alignItems: 'center', gap: 8,
        padding: '6px 12px', fontSize: 10, fontWeight: 700, letterSpacing: '0.14em', textTransform: 'uppercase',
      }}>
        <span className="skew-tag-inner" style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
          <span className="pulse-dot" style={{ width: 6, height: 6, background: 'var(--orange)', borderRadius: '50%' }} />
          {draft.hero.eyebrow}
        </span>
      </div>
      <h2 className="font-display" style={{ fontSize: 24, lineHeight: 1, margin: '14px 0 10px', letterSpacing: '-0.02em' }}>
        {parts[0]}
        {parts.length > 1 && <>
          <span style={{ position: 'relative', whiteSpace: 'nowrap' }}>
            <span style={{ position: 'absolute', left: 0, right: 0, bottom: '8%', height: '38%', background: 'var(--orange)', opacity: 0.85, transform: 'skewX(-6deg)' }} />
            <span style={{ position: 'relative' }}>{hl}</span>
          </span>
          {parts[1]}
        </>}
      </h2>
      <p style={{ color: 'var(--grey-600)', fontSize: 12.5, lineHeight: 1.5, margin: 0 }}>{draft.hero.sub}</p>
      <div style={{ display: 'flex', gap: 8, marginTop: 14 }}>
        <span className="font-display" style={{ background: 'var(--orange)', color: '#fff', padding: '8px 14px', fontSize: 11, letterSpacing: '0.06em', textTransform: 'uppercase', borderRadius: 4, boxShadow: '0 2px 8px rgba(241,86,35,0.25)' }}>{draft.hero.ctaPrimary}</span>
        <span className="font-display" style={{ background: '#fff', color: 'var(--ink)', padding: '7px 13px', fontSize: 11, letterSpacing: '0.06em', textTransform: 'uppercase', border: '1.5px solid var(--ink)' }}>{draft.hero.ctaSecondary}</span>
      </div>
    </div>
  );
}

function TicketPreview({ draft }) {
  return (
    <div style={{ background: 'var(--grey-50)', padding: 14, display: 'flex', justifyContent: 'center' }}>
      <div style={{ background: '#fff', border: '1px solid var(--grey-200)', borderRadius: 8, boxShadow: '0 2px 12px rgba(17,6,24,0.08)', maxWidth: 240, width: '100%', overflow: 'hidden' }}>
        <div style={{ background: 'var(--ink)', color: '#fff', padding: '8px 14px', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 700 }}>
          <span style={{ color: 'var(--orange)' }}>Match day pass</span>
        </div>
        <div className="stripes-bg" style={{ height: 6 }} />
        <div style={{ padding: 14 }}>
          <div className="font-display" style={{ fontSize: 16, letterSpacing: '-0.01em' }}>
            {draft.ticket.title}<br />
            <span style={{ color: 'var(--orange)' }}>{draft.ticket.year}</span>
          </div>
          <div style={{ fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--grey-600)', marginTop: 6, fontWeight: 600 }}>{draft.ticket.region}</div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginTop: 10 }}>
            <div style={{ border: '1.5px solid var(--ink)', padding: '6px 8px' }}>
              <div style={{ fontSize: 9, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--grey-600)', fontWeight: 700 }}>Outlets</div>
              <div className="font-display" style={{ fontSize: 18 }}>{draft.ticket.outlets}</div>
            </div>
            <div style={{ border: '1.5px solid var(--ink)', padding: '6px 8px' }}>
              <div style={{ fontSize: 9, letterSpacing: '0.16em', textTransform: 'uppercase', color: 'var(--grey-600)', fontWeight: 700 }}>Matches</div>
              <div className="font-display" style={{ fontSize: 18 }}>{draft.ticket.matches}</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ============================================================
   SETTINGS
   ============================================================ */
function AdminSettings({ ctx }) {
  const [accentColor, setAccentColor] = useState('#ee5722');
  const [oldPw, setOldPw] = useState('');
  const [newPw, setNewPw] = useState('');
  const [newPw2, setNewPw2] = useState('');

  function changePassword() {
    if (!oldPw || !newPw) return;
    if (newPw !== newPw2) { ctx.setToast({ message: 'Passwords don\'t match.', tone: 'error' }); return; }
    if (newPw.length < 8) { ctx.setToast({ message: 'Password must be at least 8 characters.', tone: 'error' }); return; }
    ctx.setToast({ message: 'Password updated. Sign in again on other devices.', tone: 'success' });
    setOldPw(''); setNewPw(''); setNewPw2('');
  }
  function rotateSecret(which) {
    ctx.setToast({ message: `${which} rotated. Update your Vercel env var.`, tone: 'info' });
  }

  return (
    <AdminSection
      title="Settings"
      sub="Administrator account, brand, and infrastructure secrets."
    >
      <div className="admin-2col" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 18 }}>
        <Panel title="Admin password">
          <div style={{ display: 'grid', gap: 12 }}>
            <FieldRow label="Current password" value={oldPw} onChange={setOldPw} />
            <FieldRow label="New password" value={newPw} onChange={setNewPw} hint="At least 8 chars" />
            <FieldRow label="Confirm new password" value={newPw2} onChange={setNewPw2} />
            <div>
              <AdminBtn kind="primary" icon="check" onClick={changePassword}>Update password</AdminBtn>
            </div>
          </div>
        </Panel>

        <Panel title="Brand accent">
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <input type="color" value={accentColor} onChange={(e) => setAccentColor(e.target.value)}
              style={{ width: 56, height: 56, border: '1.5px solid var(--grey-300)', padding: 4, cursor: 'pointer' }} />
            <div style={{ flex: 1 }}>
              <FormLabel>Primary orange</FormLabel>
              <input value={accentColor} onChange={(e) => setAccentColor(e.target.value)} className="font-mono" style={{ ...inputStyle, fontFamily: "'JetBrains Mono', monospace" }} />
            </div>
          </div>
          <p style={{ fontSize: 12, color: 'var(--grey-500)', marginTop: 12, marginBottom: 0 }}>
            Pulled from the SunFront logo. Changing this re-themes buttons, accents, and the starburst echo across the public site.
          </p>
          <div style={{ marginTop: 12 }}>
            <AdminBtn kind="primary" icon="check" onClick={() => ctx.setToast({ message: 'Brand accent saved.', tone: 'success' })}>Apply theme</AdminBtn>
          </div>
        </Panel>

        <Panel title="Infrastructure secrets">
          <SecretRow label="Session signing secret" value="••••••••••••••••••••••••••••5f3a" onRotate={() => rotateSecret('SESSION_SECRET')} />
          <SecretRow label="Cron endpoint secret"   value="••••••••••••••••••••••••••••a82c" onRotate={() => rotateSecret('CRON_SECRET')} />
          <p style={{ fontSize: 12, color: 'var(--grey-500)', margin: '14px 0 0' }}>
            Rotating invalidates all admin sessions and the Vercel cron until you update env vars.
          </p>
        </Panel>

        <Panel title="Database & exports">
          <SettingRow label="Postgres host">
            <span className="font-mono" style={{ fontSize: 12 }}>ep-cool-rain-83.eu-west-2.aws.neon.tech</span>
          </SettingRow>
          <SettingRow label="Total predictions stored">
            <span className="font-display" style={{ fontSize: 18 }}><AnimatedCounter value={ctx.livePredictions.length} /></span>
          </SettingRow>
          <div style={{ marginTop: 14, display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            <AdminBtn kind="outline" icon="receipt" onClick={() => ctx.setToast({ message: 'Full database export queued.', tone: 'info' })}>Export full DB</AdminBtn>
            <AdminBtn kind="ghost" onClick={() => ctx.setToast({ message: 'Cron synced.', tone: 'success' })}>Run cron now</AdminBtn>
          </div>
        </Panel>
      </div>

      <style>{`
        @media (max-width: 900px) {
          .admin-2col { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </AdminSection>
  );
}

function SecretRow({ label, value, onRotate }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12,
      padding: '12px 0', borderTop: '1px solid var(--grey-100)',
    }}>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--grey-600)', fontWeight: 700 }}>{label}</div>
        <div className="font-mono" style={{ fontSize: 12.5, marginTop: 4, overflow: 'hidden', textOverflow: 'ellipsis' }}>{value}</div>
      </div>
      <AdminBtn kind="ghost" onClick={onRotate}>Rotate</AdminBtn>
    </div>
  );
}
function SettingRow({ label, children }) {
  return (
    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '8px 0', borderTop: '1px solid var(--grey-100)' }}>
      <span style={{ fontSize: 12.5, color: 'var(--grey-600)' }}>{label}</span>
      <span style={{ textAlign: 'right' }}>{children}</span>
    </div>
  );
}

/* ============================================================
   BILL DATA BROWSER (read-only: bill_usage, bill_entries, prediction_change_log)
   ============================================================ */
function AdminBillData({ ctx }) {
  const [data, setData] = useState(null);
  const [error, setError] = useState('');
  const [view, setView] = useState('usage'); // 'usage' | 'entries' | 'log'
  const [loading, setLoading] = useState(false);
  const [lastUpdated, setLastUpdated] = useState(null);

  const loadData = React.useCallback((active = { value: true }) => {
    setLoading(true);
    fetch('/api/get-bill-data', { headers: { 'x-admin-key': ctx.adminToken } })
      .then(r => r.json())
      .then(d => {
        if (!active.value) return;
        if (d.billUsage) { setData(d); setError(''); setLastUpdated(Date.now()); }
        else { setError(d.error || 'Could not load bill data.'); }
      })
      .catch(() => { if (active.value) setError('Network error while loading bill data.'); })
      .finally(() => { if (active.value) setLoading(false); });
  }, [ctx.adminToken]);

  useEffect(() => {
    const active = { value: true };
    loadData(active);
    const id = setInterval(() => loadData(active), 30000);
    return () => { active.value = false; clearInterval(id); };
  }, [loadData]);

  const VIEWS = [
    { key: 'usage',   label: 'Bill usage',   count: data && data.billUsage.length },
    { key: 'entries', label: 'Bill entries', count: data && data.billEntries.length },
    { key: 'log',     label: 'Change log',   count: data && data.changeLog.length },
  ];

  return (
    <AdminSection
      title="Bill data"
      sub="Read-only view of bill_usage, bill_entries and prediction_change_log from Supabase. Auto-refreshes every 30 s."
      right={
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          {lastUpdated && (
            <span style={{ fontSize: 11.5, color: 'var(--grey-500)' }}>
              Updated {new Date(lastUpdated).toLocaleTimeString('en-MV', { timeZone: 'Indian/Maldives', hour12: false })}
            </span>
          )}
          <AdminBtn kind="ghost" icon="bolt" disabled={loading} onClick={() => loadData({ value: true })}>
            {loading ? 'Refreshing…' : 'Refresh now'}
          </AdminBtn>
        </div>
      }
    >
      <div style={{
        background: '#fff8f3', border: '1.5px solid var(--orange-100)',
        padding: '10px 14px', display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14,
        fontSize: 12.5, color: 'var(--ink)',
      }}>
        <span style={{ width: 8, height: 8, background: 'var(--orange)', flexShrink: 0 }} />
        <span>Read-only. No edits, deletes, or settlements can be made from this screen.</span>
      </div>

      {!data && !error && (
        <div style={{ padding: '20px 0', color: 'var(--grey-500)', fontSize: 13.5 }}>Loading…</div>
      )}
      {error && (
        <div style={{
          padding: '10px 14px', background: '#fee2e2', color: '#b91c1c',
          border: '1px solid #fecaca', fontSize: 13, marginBottom: 12,
        }}>
          ⚠ {error}
          <span style={{ display: 'block', marginTop: 4, fontSize: 12, color: '#7f1d1d' }}>
            Check SUPABASE_URL / SUPABASE_SERVICE_KEY in Vercel env vars.
          </span>
        </div>
      )}

      {data && (
        <>
          <div style={{ display: 'flex', gap: 8, marginBottom: 14, flexWrap: 'wrap' }}>
            {VIEWS.map(v => (
              <button key={v.key} onClick={() => setView(v.key)} style={{
                background: view === v.key ? 'var(--ink)' : '#fff',
                color: view === v.key ? '#fff' : 'var(--ink)',
                border: '1.5px solid var(--ink)',
                padding: '8px 16px', fontSize: 12.5, fontWeight: 700,
                letterSpacing: '0.04em', cursor: 'pointer',
              }}>
                {v.label} <span style={{ opacity: 0.6 }}>({v.count ?? 0})</span>
              </button>
            ))}
          </div>

          {view === 'usage'   && <BillUsageTable rows={data.billUsage} />}
          {view === 'entries' && <BillEntriesTable rows={data.billEntries} />}
          {view === 'log'     && <ChangeLogTable rows={data.changeLog} />}
        </>
      )}
    </AdminSection>
  );
}

/* Generic search + paginate table, shared by the three bill-data views. */
function PagedDataTable({ rows, searchKeys, columns, emptyLabel, pageSize = 12 }) {
  const [q, setQ] = useState('');
  const [page, setPage] = useState(0);

  const filtered = useMemo(() => {
    if (!q) return rows;
    const Q = q.toLowerCase();
    return rows.filter(r => searchKeys.some(k => String(r[k] ?? '').toLowerCase().includes(Q)));
  }, [rows, q, searchKeys]);

  const pages = Math.max(1, Math.ceil(filtered.length / pageSize));
  const visible = filtered.slice(page * pageSize, (page + 1) * pageSize);

  return (
    <Panel padding={0}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--grey-200)' }}>
        <FormLabel>Search</FormLabel>
        <input value={q} onChange={(e) => { setQ(e.target.value); setPage(0); }} placeholder="Search…" style={{ ...inputStyle, maxWidth: 280 }} />
      </div>
      <div style={{ overflowX: 'auto' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 760 }}>
          <thead>
            <tr style={{ background: 'var(--grey-50)' }}>
              {columns.map(c => <Th key={c.key} align={c.align}>{c.label}</Th>)}
            </tr>
          </thead>
          <tbody>
            {visible.map((r, i) => (
              <tr key={r.id ?? r.ID ?? i} style={{ borderTop: '1px solid var(--grey-100)' }}>
                {columns.map(c => <Td key={c.key} align={c.align}>{c.render ? c.render(r) : (r[c.key] ?? '—')}</Td>)}
              </tr>
            ))}
            {visible.length === 0 && (
              <tr><td colSpan={columns.length} style={{ padding: 32, textAlign: 'center', color: 'var(--grey-500)' }}>{emptyLabel}</td></tr>
            )}
          </tbody>
        </table>
      </div>
      <div style={{
        padding: '12px 18px', borderTop: '1px solid var(--grey-200)',
        display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 10,
      }}>
        <div style={{ fontSize: 12.5, color: 'var(--grey-600)' }}>
          Showing {filtered.length === 0 ? 0 : page * pageSize + 1}–{Math.min((page + 1) * pageSize, filtered.length)} of {filtered.length}
        </div>
        <div style={{ display: 'flex', gap: 6 }}>
          <AdminBtn kind="ghost" disabled={page === 0} onClick={() => setPage(p => p - 1)}>← Prev</AdminBtn>
          <div style={{ display: 'flex', alignItems: 'center', padding: '0 10px', fontSize: 12.5, color: 'var(--grey-700)' }}>
            Page {page + 1} / {pages}
          </div>
          <AdminBtn kind="ghost" disabled={page + 1 >= pages} onClick={() => setPage(p => p + 1)}>Next →</AdminBtn>
        </div>
      </div>
    </Panel>
  );
}

function BillUsageTable({ rows }) {
  const columns = [
    { key: 'bill_number',     label: 'Bill #',           render: r => <span className="font-mono" style={{ fontSize: 12.5 }}>{r.bill_number}</span> },
    { key: 'amount_myr',      label: 'Amount (MVR)',     render: r => <span className="font-mono" style={{ fontWeight: 700 }}>{Number(r.amount_myr).toFixed(2)}</span> },
    { key: 'votes',           label: 'Votes used / max', render: r => `${r.used_votes} / ${r.max_votes}` },
    { key: 'remaining_votes', label: 'Remaining' },
    { key: 'bound_name',      label: 'Bound name',       render: r => r.bound_name || '—' },
    { key: 'bound_phone',     label: 'Bound phone',      render: r => r.bound_phone || '—' },
    { key: 'created_at',      label: 'Created', align: 'right', render: r => timeAgo(new Date(r.created_at).getTime()) },
  ];
  return <PagedDataTable rows={rows} searchKeys={['bill_number', 'bound_name', 'bound_phone']} columns={columns} emptyLabel="No bill usage rows." />;
}

function BillEntriesTable({ rows }) {
  const columns = [
    { key: 'ID',           label: 'ID' },
    { key: 'bill_number',  label: 'Bill #',       render: r => <span className="font-mono" style={{ fontSize: 12.5 }}>{r.bill_number}</span> },
    { key: 'amount_myr',   label: 'Amount (MVR)', render: r => <span className="font-mono" style={{ fontWeight: 700 }}>{Number(r.amount_myr).toFixed(2)}</span> },
    { key: 'Source',       label: 'Source' },
    { key: 'receipt_date', label: 'Receipt date', render: r => r.receipt_date || '—' },
    { key: 'Shop',         label: 'Shop',         render: r => r.Shop || '—' },
    { key: 'ShopID',       label: 'Shop ID',      render: r => r.ShopID || '—' },
    { key: 'created_at',   label: 'Created', align: 'right', render: r => timeAgo(new Date(r.created_at).getTime()) },
  ];
  return <PagedDataTable rows={rows} searchKeys={['bill_number', 'Source', 'Shop', 'ShopID']} columns={columns} emptyLabel="No bill entries." />;
}

function ChangeLogTable({ rows }) {
  const columns = [
    { key: 'changed_at',     label: 'Time', render: r => timeAgo(new Date(r.changed_at).getTime()) },
    { key: 'action',         label: 'Action', render: r => (
      <span style={{ textTransform: 'uppercase', fontWeight: 700, fontSize: 11, letterSpacing: '0.06em', color: r.action === 'submit' ? 'var(--orange)' : 'var(--ink)' }}>
        {r.action}
      </span>
    ) },
    { key: 'bill_number',    label: 'Bill #',         render: r => <span className="font-mono" style={{ fontSize: 12.5 }}>{r.bill_number}</span> },
    { key: 'customer_phone', label: 'Phone',          render: r => <span className="font-mono" style={{ fontSize: 12.5 }}>{r.customer_phone}</span> },
    { key: 'match_label',    label: 'Match',          render: r => r.match_label || ('Match ' + r.match_id) },
    { key: 'pick',           label: 'Pick change',    render: r => r.old_pick ? `${r.old_pick} → ${r.new_pick}` : `→ ${r.new_pick}` },
    { key: 'amount_myr',     label: 'Amount (MVR)', align: 'right', render: r => r.amount_myr != null ? Number(r.amount_myr).toFixed(2) : '—' },
  ];
  return <PagedDataTable rows={rows} searchKeys={['bill_number', 'customer_phone', 'match_label']} columns={columns} emptyLabel="No change log entries." />;
}

Object.assign(window, {
  AdminPredictions, AdminOutlets, AdminContent, AdminSettings, AdminBillData,
});
