// Admin interface. Gated on #admin hash + ADMIN_TOKEN.
// One file, one component tree: gate → list → form/roster.
//
// All writes go through window.BACKEND_URL with text/plain Content-Type
// (same CORS workaround as the public signup flow).

const TOKEN_KEY = 'afsws-admin-token';

// ── Token gate ───────────────────────────────────────────────────────────
function loadToken() {
  return sessionStorage.getItem(TOKEN_KEY) || '';
}
function saveToken(tok) {
  sessionStorage.setItem(TOKEN_KEY, tok);
}
function clearToken() {
  sessionStorage.removeItem(TOKEN_KEY);
}

// ── Admin API helpers ────────────────────────────────────────────────────
async function adminFetchEvents(token) {
  const url = window.BACKEND_URL + '?action=getEvents&includeArchived=true&token=' + encodeURIComponent(token);
  const resp = await fetch(url);
  if (!resp.ok) throw new Error('HTTP ' + resp.status);
  const data = await resp.json();
  if (data.error) throw new Error(data.error);
  return data.events || [];
}

async function adminFetchRoster(eventId, token) {
  const url = window.BACKEND_URL + '?action=getRoster&eventId=' + encodeURIComponent(eventId) + '&token=' + encodeURIComponent(token);
  const resp = await fetch(url);
  if (!resp.ok) throw new Error('HTTP ' + resp.status);
  const data = await resp.json();
  if (data.error) throw new Error(data.error);
  return data.rows || [];
}

async function adminPost(action, body) {
  const resp = await fetch(window.BACKEND_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'text/plain;charset=utf-8' },
    body: JSON.stringify({ action, ...body }),
  });
  if (!resp.ok) throw new Error('HTTP ' + resp.status);
  const data = await resp.json();
  if (data.error) throw new Error(data.error);
  return data;
}

// ── Main admin wrapper ───────────────────────────────────────────────────
function Admin({ t, onExit }) {
  const [token, setToken] = React.useState(loadToken());
  const [events, setEvents] = React.useState([]);
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [editingId, setEditingId] = React.useState(null); // event id, 'new', or null
  const [rosterFor, setRosterFor] = React.useState(null); // event id or null

  const loadEvents = React.useCallback(async (tok) => {
    setLoading(true);
    setError(null);
    try {
      const list = await adminFetchEvents(tok || token);
      setEvents(list);
    } catch (err) {
      setError(err.message);
      if (/unauthor/i.test(err.message)) {
        clearToken();
        setToken('');
      }
    } finally {
      setLoading(false);
    }
  }, [token]);

  React.useEffect(() => {
    if (token) loadEvents(token);
  }, [token]);

  const handleSignIn = (tok) => {
    saveToken(tok);
    setToken(tok);
  };

  const handleSignOut = () => {
    clearToken();
    setToken('');
    setEvents([]);
  };

  const handleSaved = () => {
    setEditingId(null);
    loadEvents();
  };

  // Gate
  if (!token) {
    return <AdminGate t={t} onSignIn={handleSignIn} onExit={onExit} />;
  }

  // Editing form (new or existing)
  if (editingId) {
    const existing = editingId === 'new' ? null : events.find(e => e.id === editingId);
    return (
      <AdminForm
        t={t}
        token={token}
        event={existing}
        onCancel={() => setEditingId(null)}
        onSaved={handleSaved}
      />
    );
  }

  // Roster view
  if (rosterFor) {
    const event = events.find(e => e.id === rosterFor);
    return (
      <AdminRoster
        t={t}
        token={token}
        event={event}
        onBack={() => setRosterFor(null)}
      />
    );
  }

  // Main list
  return (
    <AdminList
      t={t}
      events={events}
      loading={loading}
      error={error}
      onRefresh={() => loadEvents()}
      onNew={() => setEditingId('new')}
      onEdit={(id) => setEditingId(id)}
      onArchive={async (id) => {
        if (!confirm('Archive this event? It will be hidden from the public calendar.')) return;
        try {
          await adminPost('deleteEvent', { id, token });
          loadEvents();
        } catch (err) { alert('Archive failed: ' + err.message); }
      }}
      onRestore={async (id) => {
        try {
          await adminPost('updateEvent', { id, status: 'active', token });
          loadEvents();
        } catch (err) { alert('Restore failed: ' + err.message); }
      }}
      onRoster={(id) => setRosterFor(id)}
      onSendReminders={async (id) => {
        const ev = events.find(e => e.id === id);
        if (!confirm(`Send reminder emails to confirmed signups for "${ev?.title || id}"? Only rows that haven't already been reminded will receive email.`)) return;
        try {
          const resp = await adminPost('sendRemindersForEvent', { eventId: id, token });
          alert(`Reminders sent: ${resp.sent || 0}${resp.errors && resp.errors.length ? `. ${resp.errors.length} error(s) - check execution log.` : '.'}`);
        } catch (err) { alert('Send reminders failed: ' + err.message); }
      }}
      onPromoteWaitlist={async (id) => {
        if (!confirm('Promote the oldest waitlist entry to confirmed for this event? They will receive a promotion email with the OPORD.')) return;
        try {
          const resp = await adminPost('promoteWaitlist', { eventId: id, token });
          if (resp.promoted) {
            alert(`Promoted: ${resp.promoted.name.trim()} (${resp.promoted.email})`);
          } else {
            alert('No waitlist entries for this event.');
          }
          loadEvents();
        } catch (err) { alert('Promotion failed: ' + err.message); }
      }}
      onExportMetrics={async () => {
        try {
          const url = window.BACKEND_URL + '?action=getMetrics&token=' + encodeURIComponent(token);
          const resp = await fetch(url);
          if (!resp.ok) throw new Error('HTTP ' + resp.status);
          const data = await resp.json();
          if (data.error) throw new Error(data.error);
          if (!window.XLSX) throw new Error('Spreadsheet library not loaded. Refresh the page and try again.');
          const wb = window.XLSX.utils.book_new();
          const perEventSheet = window.XLSX.utils.json_to_sheet(data.perEvent || []);
          const signupsSheet  = window.XLSX.utils.json_to_sheet(data.signups || []);
          window.XLSX.utils.book_append_sheet(wb, perEventSheet, 'Per Event');
          window.XLSX.utils.book_append_sheet(wb, signupsSheet,  'Signups');
          const stamp = new Date().toISOString().slice(0, 10);
          window.XLSX.writeFile(wb, `metrics_${stamp}.xlsx`);
        } catch (err) { alert('Metrics export failed: ' + err.message); }
      }}
      onSignOut={handleSignOut}
      onExit={onExit}
    />
  );
}

// ── Gate (password prompt) ───────────────────────────────────────────────
function AdminGate({ t, onSignIn, onExit }) {
  const [input, setInput] = React.useState('');
  const [submitting, setSubmitting] = React.useState(false);
  const [err, setErr] = React.useState(null);

  const submit = async (e) => {
    e.preventDefault();
    if (!input.trim()) return;
    setSubmitting(true);
    setErr(null);
    // Validate by attempting a token-gated fetch
    try {
      await adminFetchEvents(input.trim());
      onSignIn(input.trim());
    } catch (error) {
      setErr(/unauthor/i.test(error.message) ? 'Wrong token.' : error.message);
      setSubmitting(false);
    }
  };

  return (
    <div style={{
      minHeight: '100vh', background: t.bg, color: t.fg,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 24,
    }}>
      <div style={{ maxWidth: 420, width: '100%' }}>
        <div style={{
          fontFamily: 'Barlow, sans-serif', fontWeight: 400, fontSize: 11,
          letterSpacing: '0.35em', color: t.brass, marginBottom: 12,
        }}>// ADMIN</div>
        <h1 style={{
          fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 36,
          letterSpacing: '0.02em', lineHeight: 1, margin: '0 0 28px',
        }}>Restricted Access</h1>
        <form onSubmit={submit}>
          <label style={{
            display: 'block',
            fontFamily: 'Barlow, sans-serif', fontSize: 11,
            letterSpacing: '0.3em', color: t.dim, marginBottom: 8,
          }}>ADMIN TOKEN</label>
          <input
            type="password"
            value={input}
            onChange={(e) => setInput(e.target.value)}
            autoFocus
            style={{
              width: '100%', padding: '12px 14px',
              background: t.cellBg, color: t.fg,
              border: `1px solid ${t.line}`,
              fontFamily: 'ui-monospace, Menlo, monospace', fontSize: 14,
              boxSizing: 'border-box',
            }}
          />
          {err && (
            <div style={{
              fontFamily: 'Barlow, sans-serif', fontSize: 12,
              color: '#e66', marginTop: 10,
            }}>{err}</div>
          )}
          <div style={{ display: 'flex', gap: 10, marginTop: 20 }}>
            <button
              type="submit"
              disabled={submitting}
              style={{
                flex: 1, padding: '12px 16px',
                background: t.brass, color: '#0F1114', border: 'none',
                fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 12,
                letterSpacing: '0.25em', cursor: submitting ? 'wait' : 'pointer',
                opacity: submitting ? 0.6 : 1,
              }}
            >{submitting ? 'CHECKING...' : 'UNLOCK'}</button>
            <button
              type="button"
              onClick={onExit}
              style={{
                padding: '12px 16px',
                background: 'transparent', color: t.fg,
                border: `1px solid ${t.line}`,
                fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 12,
                letterSpacing: '0.25em', cursor: 'pointer',
              }}
            >EXIT</button>
          </div>
        </form>
      </div>
    </div>
  );
}

// ── List view ────────────────────────────────────────────────────────────
function AdminList({ t, events, loading, error, onRefresh, onNew, onEdit, onArchive, onRestore, onRoster, onSendReminders, onPromoteWaitlist, onExportMetrics, onSignOut, onExit }) {
  const active = events.filter(e => e.status !== 'archived');
  const archived = events.filter(e => e.status === 'archived');
  const [showArchived, setShowArchived] = React.useState(false);

  return (
    <div style={{ minHeight: '100vh', background: t.bg, color: t.fg, padding: '32px 24px 80px' }}>
      <div style={{ maxWidth: 1100, margin: '0 auto' }}>
        {/* Header */}
        <div style={{
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          flexWrap: 'wrap', gap: 12, marginBottom: 28,
        }}>
          <div>
            <div style={{
              fontFamily: 'Barlow, sans-serif', fontSize: 11,
              letterSpacing: '0.35em', color: t.brass, marginBottom: 6,
            }}>// ADMIN</div>
            <h1 style={{
              fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 32,
              letterSpacing: '0.02em', margin: 0,
            }}>Operations Control</h1>
          </div>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            <button onClick={onRefresh} style={btnSecondary(t)}>REFRESH</button>
            <button onClick={onExportMetrics} style={btnSecondary(t)}>↓ METRICS .XLSX</button>
            <button onClick={onNew} style={btnPrimary(t)}>+ NEW EVENT</button>
            <button onClick={onSignOut} style={btnSecondary(t)}>SIGN OUT</button>
            <button onClick={onExit} style={btnSecondary(t)}>EXIT</button>
          </div>
        </div>

        {loading && <div style={dimNotice(t)}>LOADING</div>}
        {error && <div style={{ ...dimNotice(t), color: '#e66' }}>ERROR: {error}</div>}

        {/* Active events */}
        {!loading && (
          <>
            <SectionHeader t={t} label="ACTIVE" count={active.length} />
            {active.length === 0 ? (
              <div style={dimNotice(t)}>NO ACTIVE EVENTS</div>
            ) : (
              active.map(ev => (
                <EventRow
                  key={ev.id}
                  t={t}
                  event={ev}
                  onEdit={() => onEdit(ev.id)}
                  onArchive={() => onArchive(ev.id)}
                  onRoster={() => onRoster(ev.id)}
                  onSendReminders={() => onSendReminders(ev.id)}
                  onPromoteWaitlist={() => onPromoteWaitlist(ev.id)}
                />
              ))
            )}

            {/* Archived events — collapsed by default */}
            <div style={{ marginTop: 36 }}>
              <button
                onClick={() => setShowArchived(s => !s)}
                style={{
                  background: 'transparent', border: 'none', color: t.dim, padding: 0,
                  fontFamily: 'Barlow, sans-serif', fontSize: 11, fontWeight: 400,
                  letterSpacing: '0.3em', cursor: 'pointer',
                }}
              >
                {showArchived ? '▼' : '▶'} ARCHIVED ({archived.length})
              </button>
              {showArchived && archived.map(ev => (
                <EventRow
                  key={ev.id}
                  t={t}
                  event={ev}
                  archived
                  onEdit={() => onEdit(ev.id)}
                  onRestore={() => onRestore(ev.id)}
                  onRoster={() => onRoster(ev.id)}
                />
              ))}
            </div>
          </>
        )}
      </div>
    </div>
  );
}

function SectionHeader({ t, label, count }) {
  return (
    <div style={{
      fontFamily: 'Barlow, sans-serif', fontSize: 11,
      letterSpacing: '0.3em', color: t.brass, marginBottom: 14,
    }}>{label} · {count}</div>
  );
}

function EventRow({ t, event, archived, onEdit, onArchive, onRestore, onRoster, onSendReminders, onPromoteWaitlist }) {
  const cap = event.capacity || 0;
  const signed = event.signed || 0;
  const pct = cap ? Math.round(signed / cap * 100) : null;
  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: 'minmax(0, 1fr) auto',
      gap: 16, padding: '16px 18px', marginBottom: 8,
      background: t.cellBg, border: `1px solid ${t.line}`,
      opacity: archived ? 0.55 : 1,
    }}>
      <div style={{ minWidth: 0 }}>
        <div style={{
          fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 16,
          marginBottom: 4, letterSpacing: '0.02em',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>{event.title || '(untitled)'}</div>
        <div style={{
          fontFamily: 'Barlow, sans-serif', fontSize: 12, color: t.dim,
          display: 'flex', gap: 14, flexWrap: 'wrap',
        }}>
          <span>{event.date || 'no date'}</span>
          <span>{event.time}{event.endTime ? ' - ' + event.endTime : ''}</span>
          <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{event.location || 'no location'}</span>
          <span>{cap ? `${signed}/${cap}${pct !== null ? ` (${pct}%)` : ''}` : `${signed} signed (unlimited)`}</span>
          <span style={{ fontFamily: 'ui-monospace, Menlo, monospace', fontSize: 10 }}>{event.id}</span>
        </div>
      </div>
      <div style={{ display: 'flex', gap: 6, alignItems: 'center', flexWrap: 'wrap', justifyContent: 'flex-end' }}>
        <button onClick={onRoster} style={btnGhost(t)}>ROSTER</button>
        {!archived && onSendReminders && (
          <button onClick={onSendReminders} style={btnGhost(t)}>REMINDERS</button>
        )}
        {!archived && onPromoteWaitlist && (
          <button onClick={onPromoteWaitlist} style={btnGhost(t)}>PROMOTE</button>
        )}
        <button onClick={onEdit} style={btnGhost(t)}>EDIT</button>
        {archived
          ? <button onClick={onRestore} style={btnGhost(t)}>RESTORE</button>
          : <button onClick={onArchive} style={btnDanger(t)}>ARCHIVE</button>}
      </div>
    </div>
  );
}

// ── Event form ───────────────────────────────────────────────────────────
function AdminForm({ t, token, event, onCancel, onSaved }) {
  const isNew = !event;
  const [form, setForm] = React.useState(() => ({
    title: event?.title || '',
    date: event?.date || '',
    time: event?.time || '',
    endTime: event?.endTime || '',
    location: event?.location || '',
    city: event?.city || '',
    type: event?.type || '',
    tag: event?.tag || 'ALL LEVELS',
    capacity: event?.capacity != null ? String(event.capacity) : '0',
    image: event?.image || '',
    opordUrl: event?.opordUrl || event?.opord?.url || '',
    opordFilename: event?.opordFilename || event?.opord?.filename || '',
    brief: event?.brief || '',
    valueProp: event?.valueProp || '',
    details: event?.details || '',
    activities: Array.isArray(event?.activities) ? event.activities.join('\n') : (event?.activities || ''),
    requirements: Array.isArray(event?.requirements) ? event.requirements.join('\n') : (event?.requirements || ''),
    whatToExpect: event?.whatToExpect || '',
    eligibility: {
      who: event?.eligibility?.who || '',
      age: event?.eligibility?.age || '',
      citizenship: event?.eligibility?.citizenship || '',
      fitness: event?.eligibility?.fitness || '',
    },
    faq: Array.isArray(event?.faq) ? event.faq : [],
    host: event?.host || 'Pacific.AFSWS',
    qrCode: event?.qrCode || '',
    status: event?.status || 'active',
  }));
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState(null);

  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const setEligibility = (k, v) => setForm(f => ({ ...f, eligibility: { ...f.eligibility, [k]: v } }));
  const setFaq = (i, k, v) => setForm(f => ({
    ...f, faq: f.faq.map((item, j) => j === i ? { ...item, [k]: v } : item),
  }));
  const addFaq = () => setForm(f => ({ ...f, faq: [...f.faq, { q: '', a: '' }] }));
  const removeFaq = (i) => setForm(f => ({ ...f, faq: f.faq.filter((_, j) => j !== i) }));

  const save = async () => {
    setErr(null);
    if (!form.title.trim()) { setErr('Title is required.'); return; }
    if (!form.date) { setErr('Date is required.'); return; }

    setSaving(true);
    const payload = {
      token,
      title: form.title.trim(),
      date: form.date,
      time: form.time,
      endTime: form.endTime,
      location: form.location,
      city: form.city,
      type: form.type,
      tag: form.tag,
      capacity: form.capacity ? Number(form.capacity) : 0,
      image: form.image,
      opordUrl: form.opordUrl,
      opordFilename: form.opordFilename,
      brief: form.brief,
      valueProp: form.valueProp,
      details: form.details,
      activities: form.activities,
      requirements: form.requirements,
      whatToExpect: form.whatToExpect,
      eligibility: form.eligibility,
      faq: form.faq.filter(f => f.q.trim() || f.a.trim()),
      host: form.host,
      qrCode: form.qrCode,
      status: form.status,
    };

    try {
      if (isNew) {
        await adminPost('addEvent', payload);
      } else {
        await adminPost('updateEvent', { ...payload, id: event.id });
      }
      onSaved();
    } catch (error) {
      setErr(error.message);
      setSaving(false);
    }
  };

  return (
    <div style={{ minHeight: '100vh', background: t.bg, color: t.fg, padding: '32px 24px 80px' }}>
      <div style={{ maxWidth: 900, margin: '0 auto' }}>
        <div style={{ marginBottom: 24 }}>
          <button onClick={onCancel} style={{
            background: 'transparent', border: 'none', color: t.dim,
            fontFamily: 'Barlow, sans-serif', fontWeight: 300, fontSize: 11,
            letterSpacing: '0.2em', cursor: 'pointer', padding: 0, marginBottom: 14,
          }}>◀ BACK TO LIST</button>
          <h1 style={{
            fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 32,
            letterSpacing: '0.02em', margin: 0,
          }}>{isNew ? 'NEW EVENT' : 'EDIT EVENT'}</h1>
          {!isNew && (
            <div style={{
              fontFamily: 'ui-monospace, Menlo, monospace', fontSize: 11,
              color: t.dim, marginTop: 6,
            }}>{event.id}</div>
          )}
        </div>

        {/* Essentials */}
        <FormGroup t={t} label="ESSENTIALS">
          <Field t={t} label="Title" required value={form.title} onChange={(v) => set('title', v)} />
          <TwoCol>
            <Field t={t} label="Date" required type="date" value={form.date} onChange={(v) => set('date', v)} />
            <Field t={t} label="Capacity (0 = unlimited)" type="number" value={form.capacity} onChange={(v) => set('capacity', v)} />
          </TwoCol>
          <TwoCol>
            <Field t={t} label="Start time (24h)" type="time" value={form.time} onChange={(v) => set('time', v)} />
            <Field t={t} label="End time (24h)" type="time" value={form.endTime} onChange={(v) => set('endTime', v)} />
          </TwoCol>
          <Field t={t} label="Location (full address)" value={form.location} onChange={(v) => set('location', v)} />
          <TwoCol>
            <Field t={t} label="City (short label for calendar)" value={form.city} onChange={(v) => set('city', v)} />
            <Field t={t} label="Host" value={form.host} onChange={(v) => set('host', v)} />
          </TwoCol>
        </FormGroup>

        {/* Categorization */}
        <FormGroup t={t} label="HERO / CATEGORIZATION">
          <TwoCol>
            <SelectField t={t} label="Tag" value={form.tag} onChange={(v) => set('tag', v)} options={[
              'ALL LEVELS', 'BEGINNER', 'INTERMEDIATE', 'ADVANCED', 'AFSPECWAR DEV',
            ]} />
            <Field t={t} label="Type (e.g. Ruck, Training, Workshop)" value={form.type} onChange={(v) => set('type', v)} />
          </TwoCol>
          <Field t={t} label="Brief (calendar preview, 1 sentence)" value={form.brief} onChange={(v) => set('brief', v)} />
          <Field t={t} label="Value prop (hero tagline, 1 sentence)" value={form.valueProp} onChange={(v) => set('valueProp', v)} />
          <ImageUploadField t={t} token={token} label="Cover image" value={form.image} onChange={(v) => set('image', v)} />
        </FormGroup>

        {/* OPORD */}
        <FormGroup t={t} label="OPORD">
          <Field t={t} label="Drive file ID or full URL" value={form.opordUrl} onChange={(v) => set('opordUrl', v)} />
          <Field t={t} label="Display filename (e.g. OPORD-MyEvent.pdf)" value={form.opordFilename} onChange={(v) => set('opordFilename', v)} />
        </FormGroup>

        {/* Content */}
        <FormGroup t={t} label="CONTENT BLOCKS">
          <TextareaField t={t} label="Details (full description paragraph)" value={form.details} onChange={(v) => set('details', v)} rows={4} />
          <TextareaField t={t} label="Activities (one per line, bullet points on /events/)" value={form.activities} onChange={(v) => set('activities', v)} rows={5} />
          <TextareaField t={t} label="Requirements / What to bring (one per line)" value={form.requirements} onChange={(v) => set('requirements', v)} rows={4} />
          <TextareaField t={t} label="What to expect on arrival" value={form.whatToExpect} onChange={(v) => set('whatToExpect', v)} rows={3} />
        </FormGroup>

        {/* Eligibility */}
        <FormGroup t={t} label="ELIGIBILITY">
          <Field t={t} label="Who" value={form.eligibility.who} onChange={(v) => setEligibility('who', v)} />
          <TwoCol>
            <Field t={t} label="Age" value={form.eligibility.age} onChange={(v) => setEligibility('age', v)} />
            <Field t={t} label="Citizenship" value={form.eligibility.citizenship} onChange={(v) => setEligibility('citizenship', v)} />
          </TwoCol>
          <Field t={t} label="Fitness" value={form.eligibility.fitness} onChange={(v) => setEligibility('fitness', v)} />
        </FormGroup>

        {/* FAQ */}
        <FormGroup t={t} label="FAQ (leave empty to use site defaults)">
          {form.faq.map((item, i) => (
            <div key={i} style={{
              padding: '14px 16px', marginBottom: 10,
              background: t.cellBg, border: `1px solid ${t.line}`,
            }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
                <div style={{
                  fontFamily: 'Barlow, sans-serif', fontSize: 10,
                  letterSpacing: '0.3em', color: t.dim,
                }}>Q&A #{i + 1}</div>
                <button onClick={() => removeFaq(i)} style={{
                  background: 'transparent', border: 'none', color: '#e66',
                  fontFamily: 'Oswald, sans-serif', fontSize: 10,
                  letterSpacing: '0.2em', cursor: 'pointer', padding: 0,
                }}>REMOVE</button>
              </div>
              <Field t={t} label="Question" value={item.q} onChange={(v) => setFaq(i, 'q', v)} />
              <TextareaField t={t} label="Answer" value={item.a} onChange={(v) => setFaq(i, 'a', v)} rows={3} />
            </div>
          ))}
          <button onClick={addFaq} style={{
            ...btnSecondary(t), marginTop: 4,
          }}>+ ADD FAQ</button>
        </FormGroup>

        {/* Meta */}
        <FormGroup t={t} label="META">
          <Field t={t} label="QR code URL (optional)" value={form.qrCode} onChange={(v) => set('qrCode', v)} />
          <SelectField t={t} label="Status" value={form.status} onChange={(v) => set('status', v)} options={['active', 'archived']} />
        </FormGroup>

        {err && <div style={{
          padding: '12px 14px', marginTop: 16,
          background: 'rgba(230,100,100,0.1)', border: '1px solid #e66', color: '#e66',
          fontFamily: 'Barlow, sans-serif', fontSize: 13,
        }}>{err}</div>}

        <div style={{ display: 'flex', gap: 10, marginTop: 28 }}>
          <button onClick={save} disabled={saving} style={{
            ...btnPrimary(t), opacity: saving ? 0.6 : 1, cursor: saving ? 'wait' : 'pointer',
          }}>{saving ? 'SAVING...' : (isNew ? 'CREATE EVENT' : 'SAVE CHANGES')}</button>
          <button onClick={onCancel} disabled={saving} style={btnSecondary(t)}>CANCEL</button>
        </div>
      </div>
    </div>
  );
}

// ── Roster view ──────────────────────────────────────────────────────────
function AdminRoster({ t, token, event, onBack }) {
  const [rows, setRows] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [err, setErr] = React.useState(null);

  React.useEffect(() => {
    if (!event) return;
    setLoading(true);
    adminFetchRoster(event.id, token)
      .then(r => { setRows(r); setLoading(false); })
      .catch(e => { setErr(e.message); setLoading(false); });
  }, [event?.id]);

  const download = () => {
    if (!window.XLSX) {
      alert('Spreadsheet library not loaded. Refresh the page and try again.');
      return;
    }
    const data = rows.map(r => ({
      Timestamp: r.timestamp,
      'First Name': r.firstName,
      'Last Name': r.lastName,
      Email: r.email,
      Phone: r.phone,
      Age: r.age,
      Status: r.status,
      Source: r.source,
      Recruiter: r.recruiter,
      Careers: r.careers,
      Medical: r.medical,
      Notes: r.notes,
      'Waiver Acknowledged': r.waiverAcknowledged,
      'Email Status': r.emailStatus,
    }));
    const ws = window.XLSX.utils.json_to_sheet(data);
    const wb = window.XLSX.utils.book_new();
    window.XLSX.utils.book_append_sheet(wb, ws, 'Roster');
    const safeTitle = (event.title || 'event').replace(/[^a-z0-9]+/gi, '_').slice(0, 40);
    window.XLSX.writeFile(wb, `roster_${safeTitle}_${event.id}.xlsx`);
  };

  if (!event) return null;

  return (
    <div style={{ minHeight: '100vh', background: t.bg, color: t.fg, padding: '32px 24px 80px' }}>
      <div style={{ maxWidth: 1200, margin: '0 auto' }}>
        <button onClick={onBack} style={{
          background: 'transparent', border: 'none', color: t.dim,
          fontFamily: 'Barlow, sans-serif', fontSize: 11,
          letterSpacing: '0.2em', cursor: 'pointer', padding: 0, marginBottom: 14,
        }}>◀ BACK TO LIST</button>
        <div style={{
          display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end',
          flexWrap: 'wrap', gap: 12, marginBottom: 24,
        }}>
          <div>
            <div style={{
              fontFamily: 'Barlow, sans-serif', fontSize: 11,
              letterSpacing: '0.35em', color: t.brass, marginBottom: 6,
            }}>// ROSTER</div>
            <h1 style={{
              fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 28,
              letterSpacing: '0.02em', margin: 0,
            }}>{event.title}</h1>
            <div style={{
              fontFamily: 'Barlow, sans-serif', fontSize: 12, color: t.dim,
              marginTop: 4,
            }}>{rows.length} signup{rows.length === 1 ? '' : 's'} · {event.date} · {event.location}</div>
          </div>
          <button onClick={download} disabled={rows.length === 0} style={{
            ...btnPrimary(t), opacity: rows.length === 0 ? 0.4 : 1,
          }}>↓ DOWNLOAD .XLSX</button>
        </div>

        {loading && <div style={dimNotice(t)}>LOADING ROSTER</div>}
        {err && <div style={{ ...dimNotice(t), color: '#e66' }}>ERROR: {err}</div>}

        {!loading && !err && rows.length === 0 && (
          <div style={dimNotice(t)}>NO SIGNUPS YET</div>
        )}

        {!loading && rows.length > 0 && (
          <div style={{ overflowX: 'auto' }}>
            <table style={{
              width: '100%', borderCollapse: 'collapse',
              fontFamily: 'Barlow, sans-serif', fontSize: 13,
            }}>
              <thead>
                <tr style={{ textAlign: 'left', borderBottom: `1px solid ${t.line}` }}>
                  {['#', 'Name', 'Email', 'Phone', 'Age', 'Status', 'Careers', 'Timestamp'].map(h => (
                    <th key={h} style={{
                      padding: '10px 12px',
                      fontFamily: 'Barlow, sans-serif', fontWeight: 600, fontSize: 10,
                      letterSpacing: '0.25em', color: t.dim, textTransform: 'uppercase',
                    }}>{h}</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {rows.map((r, i) => (
                  <tr key={i} style={{ borderBottom: `1px solid ${t.line}` }}>
                    <td style={rosterCell(t)}>{i + 1}</td>
                    <td style={rosterCell(t)}>{r.firstName} {r.lastName}</td>
                    <td style={rosterCell(t)}>{r.email}</td>
                    <td style={rosterCell(t)}>{r.phone}</td>
                    <td style={rosterCell(t)}>{r.age}</td>
                    <td style={{
                      ...rosterCell(t),
                      color: r.status === 'waitlist' ? t.brass : t.fg,
                      textTransform: 'uppercase', fontSize: 11, letterSpacing: '0.1em',
                    }}>{r.status}</td>
                    <td style={rosterCell(t)}>{r.careers}</td>
                    <td style={{ ...rosterCell(t), fontFamily: 'ui-monospace, Menlo, monospace', fontSize: 11 }}>{r.timestamp}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>
    </div>
  );
}

// ── Form primitives ──────────────────────────────────────────────────────
function FormGroup({ t, label, children }) {
  return (
    <div style={{ marginBottom: 28 }}>
      <div style={{
        fontFamily: 'Barlow, sans-serif', fontSize: 11, fontWeight: 600,
        letterSpacing: '0.3em', color: t.brass, marginBottom: 14,
        paddingBottom: 8, borderBottom: `1px solid ${t.line}`,
      }}>// {label}</div>
      {children}
    </div>
  );
}

function TwoCol({ children }) {
  return (
    <div style={{
      display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14,
    }}>{children}</div>
  );
}

function Field({ t, label, value, onChange, type = 'text', required }) {
  return (
    <div style={{ marginBottom: 12 }}>
      <label style={fieldLabelStyle(t)}>{label}{required && <span style={{ color: t.brass }}> *</span>}</label>
      <input
        type={type}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        style={fieldInputStyle(t)}
      />
    </div>
  );
}

function TextareaField({ t, label, value, onChange, rows = 3 }) {
  return (
    <div style={{ marginBottom: 12 }}>
      <label style={fieldLabelStyle(t)}>{label}</label>
      <textarea
        rows={rows}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        style={{ ...fieldInputStyle(t), fontFamily: 'Barlow, sans-serif', resize: 'vertical' }}
      />
    </div>
  );
}

// Upload-or-paste image field. Either drop/pick a file (uploads to Drive
// via the uploadImage action) or paste a URL directly. Shows a preview.
function ImageUploadField({ t, token, label, value, onChange }) {
  const [uploading, setUploading] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const fileInputRef = React.useRef(null);

  const handleFile = async (file) => {
    if (!file) return;
    if (!/^image\//.test(file.type)) {
      setErr('File must be an image.');
      return;
    }
    if (file.size > 10 * 1024 * 1024) {
      setErr('Image too large. Max 10MB.');
      return;
    }
    setErr(null);
    setUploading(true);
    try {
      const base64Data = await fileToBase64(file);
      const resp = await adminPost('uploadImage', {
        token,
        filename: file.name,
        mimeType: file.type,
        base64Data,
      });
      if (resp && resp.url) {
        onChange(resp.url);
      } else {
        setErr('Upload succeeded but no URL returned.');
      }
    } catch (error) {
      setErr('Upload failed: ' + error.message);
    } finally {
      setUploading(false);
      if (fileInputRef.current) fileInputRef.current.value = '';
    }
  };

  return (
    <div style={{ marginBottom: 12 }}>
      <label style={fieldLabelStyle(t)}>{label}</label>

      {/* Upload + URL row */}
      <div style={{ display: 'flex', gap: 8, alignItems: 'stretch', marginBottom: 8 }}>
        <button
          type="button"
          onClick={() => fileInputRef.current && fileInputRef.current.click()}
          disabled={uploading}
          style={{
            padding: '10px 16px', whiteSpace: 'nowrap',
            background: t.brass, color: '#0F1114', border: 'none',
            fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 11,
            letterSpacing: '0.25em',
            cursor: uploading ? 'wait' : 'pointer',
            opacity: uploading ? 0.5 : 1,
          }}
        >{uploading ? 'UPLOADING...' : '↑ UPLOAD'}</button>
        <input
          ref={fileInputRef}
          type="file"
          accept="image/*"
          style={{ display: 'none' }}
          onChange={(e) => handleFile(e.target.files && e.target.files[0])}
        />
        <input
          type="text"
          value={value}
          onChange={(e) => onChange(e.target.value)}
          placeholder="...or paste an image URL"
          style={{ ...fieldInputStyle(t), marginBottom: 0, flex: 1 }}
        />
        {value && (
          <button
            type="button"
            onClick={() => onChange('')}
            style={{
              padding: '10px 14px', whiteSpace: 'nowrap',
              background: 'transparent', color: t.dim,
              border: `1px solid ${t.line}`,
              fontFamily: 'Oswald, sans-serif', fontSize: 11,
              letterSpacing: '0.2em', cursor: 'pointer',
            }}
          >CLEAR</button>
        )}
      </div>

      {err && (
        <div style={{
          fontFamily: 'Barlow, sans-serif', fontSize: 12,
          color: '#e66', marginTop: 6,
        }}>{err}</div>
      )}

      {/* Preview */}
      {value && !err && (
        <div style={{
          marginTop: 8, padding: 10,
          background: t.cellBg, border: `1px solid ${t.line}`,
          display: 'flex', gap: 12, alignItems: 'center',
        }}>
          <img
            src={value}
            alt="Cover preview"
            onError={(e) => { e.target.style.opacity = 0.25; }}
            style={{
              width: 120, height: 80, objectFit: 'cover',
              border: `1px solid ${t.line}`, background: '#000',
              flexShrink: 0,
            }}
          />
          <div style={{
            fontFamily: 'ui-monospace, Menlo, monospace', fontSize: 11,
            color: t.dim, wordBreak: 'break-all', lineHeight: 1.4,
          }}>{value}</div>
        </div>
      )}
    </div>
  );
}

function fileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      const result = reader.result;
      const commaIdx = result.indexOf(',');
      // reader.result is a data URL; strip the "data:mime;base64," prefix.
      resolve(commaIdx >= 0 ? result.slice(commaIdx + 1) : result);
    };
    reader.onerror = () => reject(new Error('File read failed'));
    reader.readAsDataURL(file);
  });
}

function SelectField({ t, label, value, onChange, options }) {
  return (
    <div style={{ marginBottom: 12 }}>
      <label style={fieldLabelStyle(t)}>{label}</label>
      <select
        value={value}
        onChange={(e) => onChange(e.target.value)}
        style={fieldInputStyle(t)}
      >
        {options.map(o => <option key={o} value={o}>{o}</option>)}
      </select>
    </div>
  );
}

// ── Styles ───────────────────────────────────────────────────────────────
function fieldLabelStyle(t) {
  return {
    display: 'block',
    fontFamily: 'Barlow, sans-serif', fontSize: 10, fontWeight: 400,
    letterSpacing: '0.25em', color: t.dim, marginBottom: 6,
    textTransform: 'uppercase',
  };
}
function fieldInputStyle(t) {
  return {
    width: '100%', padding: '10px 12px',
    background: t.cellBg, color: t.fg,
    border: `1px solid ${t.line}`,
    fontFamily: 'Barlow, sans-serif', fontSize: 14,
    boxSizing: 'border-box',
  };
}
function btnPrimary(t) {
  return {
    padding: '10px 16px',
    background: t.brass, color: '#0F1114', border: 'none',
    fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 11,
    letterSpacing: '0.25em', cursor: 'pointer',
  };
}
function btnSecondary(t) {
  return {
    padding: '10px 16px',
    background: 'transparent', color: t.fg,
    border: `1px solid ${t.line}`,
    fontFamily: 'Oswald, sans-serif', fontWeight: 700, fontSize: 11,
    letterSpacing: '0.25em', cursor: 'pointer',
  };
}
function btnGhost(t) {
  return {
    padding: '6px 12px',
    background: 'transparent', color: t.fg,
    border: `1px solid ${t.line}`,
    fontFamily: 'Oswald, sans-serif', fontWeight: 600, fontSize: 10,
    letterSpacing: '0.2em', cursor: 'pointer',
  };
}
function btnDanger(t) {
  return {
    padding: '6px 12px',
    background: 'transparent', color: '#e66',
    border: '1px solid #e66',
    fontFamily: 'Oswald, sans-serif', fontWeight: 600, fontSize: 10,
    letterSpacing: '0.2em', cursor: 'pointer',
  };
}
function dimNotice(t) {
  return {
    textAlign: 'center', padding: '40px 24px',
    fontFamily: 'Barlow, sans-serif', fontSize: 12,
    letterSpacing: '0.25em', color: t.dim,
  };
}
function rosterCell(t) {
  return {
    padding: '12px 12px',
    fontFamily: 'Barlow, sans-serif', fontSize: 13,
    color: t.fg,
  };
}

window.Admin = Admin;
