/* global React, Btn, Eyebrow, Display, FigureNum, Wordmark, Field, Rule */
const { useState: useStateAdmin, useEffect: useEffectAdmin } = React;

const TAB_KEYS = [
  { id: "overview", label: "Overzicht", roman: "Ⅰ" },
  { id: "usage", label: "Gebruik", roman: "Ⅱ" },
  { id: "users", label: "Gebruikers", roman: "Ⅲ" },
  { id: "quizzes", label: "Quizzes", roman: "Ⅳ" },
  { id: "sessions", label: "Sessies", roman: "Ⅴ" },
  { id: "features", label: "Capabilities", roman: "Ⅵ" },
  { id: "branding", label: "Branding", roman: "Ⅶ" },
  { id: "texts", label: "Teksten", roman: "Ⅷ" },
  { id: "backup", label: "Backup", roman: "Ⅸ" },
];

function AdminScreen({ theme, user, onClose, onLogout, onSiteTextChange, onBrandingChange }) {
  const [tab, setTab] = useStateAdmin("overview");

  return (
    <div style={{ minHeight: "100vh", background: theme.bg, display: "flex", flexDirection: "column" }}>
      <header style={{
        borderBottom: `3px double ${theme.rule}`,
        padding: "14px 40px",
        display: "grid",
        gridTemplateColumns: "1fr auto 1fr",
        alignItems: "center",
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
          <button onClick={onClose} style={{
            background: "transparent", border: "none",
            fontFamily: theme.fonts.display, fontSize: 16, color: theme.fg, cursor: "pointer",
          }}>← naar dashboard</button>
          <div style={{ width: 1, height: 16, background: theme.rule }} />
          <Eyebrow theme={theme} style={{ color: theme.accent }}>── ADMIN-CONSOLE</Eyebrow>
        </div>
        <Wordmark size={100} />
        <div style={{ textAlign: "right", display: "flex", justifyContent: "flex-end", gap: 12, alignItems: "center" }}>
          <Eyebrow theme={theme}>INGELOGD ALS {user.name?.toUpperCase()}</Eyebrow>
          <button onClick={onLogout} style={{
            background: "transparent", border: `1px solid ${theme.rule}`,
            padding: "4px 10px", cursor: "pointer", color: theme.fg,
            fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.1em",
          }}>UITLOGGEN</button>
        </div>
      </header>

      <nav style={{ borderBottom: `1px solid ${theme.rule}`, display: "flex", padding: "0 40px" }}>
        {TAB_KEYS.map((t) => {
          const active = tab === t.id;
          return (
            <button key={t.id} onClick={() => setTab(t.id)} style={{
              background: "transparent", border: "none",
              padding: "14px 24px",
              cursor: "pointer",
              borderBottom: active ? `3px solid ${theme.accent}` : "3px solid transparent",
              fontFamily: theme.fonts.display,
              fontSize: 16,
              color: active ? theme.fg : theme.fgDim,
              display: "flex", gap: 10, alignItems: "center",
            }}>
              <span style={{ fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.15em", opacity: 0.7 }}>{t.roman}</span>
              {t.label}
            </button>
          );
        })}
      </nav>

      <main style={{ flex: 1, maxWidth: 1320, margin: "0 auto", width: "100%", padding: "32px 40px" }}>
        {tab === "overview" && <OverviewTab theme={theme} />}
        {tab === "usage" && <UsageTab theme={theme} />}
        {tab === "users" && <UsersTab theme={theme} currentUserId={user.id} />}
        {tab === "quizzes" && <QuizzesTab theme={theme} />}
        {tab === "sessions" && <SessionsTab theme={theme} />}
        {tab === "features" && <FeaturesTab theme={theme} />}
        {tab === "branding" && <BrandingTab theme={theme} onBrandingChange={onBrandingChange} />}
        {tab === "texts" && <TextsTab theme={theme} onSiteTextChange={onSiteTextChange} />}
        {tab === "backup" && <BackupTab theme={theme} />}
      </main>
    </div>
  );
}

// =================== TABS ===================

function OverviewTab({ theme }) {
  const [stats, setStats] = useStateAdmin(null);
  const [error, setError] = useStateAdmin(null);

  useEffectAdmin(() => {
    window.kwistApi.get("/api/admin/stats").then(setStats).catch((e) => setError(e.message));
  }, []);

  if (error) return <ErrorBox theme={theme} message={error} />;
  if (!stats) return <Loading theme={theme} />;

  const tiles = [
    ["Gebruikers", stats.users],
    ["Quizzes", stats.quizzes],
    ["Vragen", stats.questions],
    ["Sessies (totaal)", stats.sessions],
    ["Sessies (actief)", stats.activeSessions],
    ["Spelers", stats.players],
    ["Antwoorden", stats.answers],
  ];

  return (
    <div>
      <Display theme={theme} size={56} style={{ marginBottom: 8 }}>Het paneel.</Display>
      <Eyebrow theme={theme} style={{ marginBottom: 28 }}>── DE STAND VAN ZAKEN</Eyebrow>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 0, border: `1px solid ${theme.rule}` }}>
        {tiles.map(([k, v], i) => (
          <div key={k} style={{
            padding: "20px 20px",
            borderRight: (i % 4 !== 3) ? `1px solid ${theme.rule}` : "none",
            borderBottom: i < tiles.length - (tiles.length % 4 || 4) ? `1px solid ${theme.rule}` : "none",
          }}>
            <Eyebrow theme={theme}>{k}</Eyebrow>
            <FigureNum theme={theme} size={48} accent>{v}</FigureNum>
          </div>
        ))}
      </div>
    </div>
  );
}

function UsersTab({ theme, currentUserId }) {
  const [users, setUsers] = useStateAdmin(null);
  const [error, setError] = useStateAdmin(null);
  const [showForm, setShowForm] = useStateAdmin(false);
  const [form, setForm] = useStateAdmin({ email: "", password: "", name: "", isAdmin: false });
  const [formError, setFormError] = useStateAdmin(null);
  const [formBusy, setFormBusy] = useStateAdmin(false);

  const reload = () =>
    window.kwistApi.get("/api/admin/users").then((r) => setUsers(r.users)).catch((e) => setError(e.message));

  useEffectAdmin(() => { reload(); }, []);

  const toggleAdmin = async (u) => {
    await window.kwistApi.patch(`/api/admin/users/${u.id}`, { isAdmin: !u.is_admin });
    reload();
  };
  const remove = async (u) => {
    const ok = await window.kwistDialog.confirm(
      `Verwijder gebruiker "${u.email}"? Al hun quizzes en sessies gaan ook weg.`,
      { title: "Gebruiker verwijderen?", danger: true, confirmLabel: "Verwijder gebruiker" }
    );
    if (!ok) return;
    await window.kwistApi.del(`/api/admin/users/${u.id}`);
    reload();
  };

  const createUser = async (e) => {
    e?.preventDefault();
    if (formBusy) return;
    setFormError(null);
    setFormBusy(true);
    try {
      await window.kwistApi.post("/api/admin/users", form);
      setForm({ email: "", password: "", name: "", isAdmin: false });
      setShowForm(false);
      reload();
    } catch (err) {
      setFormError(err.message || "Aanmaken mislukt.");
    } finally {
      setFormBusy(false);
    }
  };

  if (error) return <ErrorBox theme={theme} message={error} />;
  if (!users) return <Loading theme={theme} />;

  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 24 }}>
        <div>
          <Display theme={theme} size={48} style={{ marginBottom: 8 }}>Gebruikers</Display>
          <Eyebrow theme={theme}>── {users.length} ACCOUNT(S)</Eyebrow>
        </div>
        <Btn theme={theme} onClick={() => setShowForm(!showForm)}>
          {showForm ? "Annuleren" : "+ Nieuw account"}
        </Btn>
      </div>

      {showForm && (
        <form onSubmit={createUser} style={{
          border: `1px solid ${theme.rule}`,
          padding: "24px 28px",
          marginBottom: 24,
          background: theme.bg2,
          display: "grid",
          gridTemplateColumns: "1fr 1fr",
          gap: "20px 32px",
        }}>
          <div style={{ gridColumn: "1 / -1" }}>
            <Eyebrow theme={theme} style={{ color: theme.accent }}>── NIEUW ACCOUNT AANMAKEN</Eyebrow>
          </div>
          <Field theme={theme} label="Volledige naam" value={form.name}
            onChange={(v) => setForm({ ...form, name: v })} placeholder="Bijv. Sanne van Dijk" />
          <Field theme={theme} label="E-mailadres" value={form.email}
            onChange={(v) => setForm({ ...form, email: v })} placeholder="naam@domein.be" />
          <Field theme={theme} label="Wachtwoord" value={form.password}
            onChange={(v) => setForm({ ...form, password: v })} placeholder="Minimaal 8 tekens" type="password" />
          <div style={{ display: "flex", alignItems: "flex-end", gap: 16 }}>
            <label style={{
              display: "flex", alignItems: "center", gap: 8, cursor: "pointer",
              fontFamily: theme.fonts.mono, fontSize: 12, letterSpacing: "0.1em", color: theme.fg,
            }}>
              <input type="checkbox" checked={form.isAdmin}
                onChange={(e) => setForm({ ...form, isAdmin: e.target.checked })}
                style={{ width: 16, height: 16, accentColor: theme.accent }} />
              ADMIN-RECHTEN
            </label>
          </div>
          <div style={{ gridColumn: "1 / -1", display: "flex", gap: 12, alignItems: "center" }}>
            {formError && (
              <div style={{
                flex: 1, padding: "8px 12px",
                border: `1px solid ${theme.accent}`, background: `${theme.accent}10`,
                color: theme.accent, fontFamily: theme.fonts.mono, fontSize: 12,
              }}>{formError}</div>
            )}
            <Btn theme={theme} type="submit" onClick={createUser} disabled={formBusy}
              style={{ marginLeft: "auto", opacity: formBusy ? 0.6 : 1 }}>
              {formBusy ? "Bezig…" : "Account aanmaken →"}
            </Btn>
          </div>
        </form>
      )}

      <Table theme={theme} cols={["E-mail", "Naam", "Quizzes", "Admin", "Aangemaakt", ""]} widths={["1.4fr", "1fr", "70px", "70px", "1fr", "auto"]}>
        {users.map((u) => (
          <Row key={u.id} theme={theme}>
            <Cell><span style={{ fontFamily: theme.fonts.mono, fontSize: 13 }}>{u.email}</span></Cell>
            <Cell>{u.name}</Cell>
            <Cell><FigureNum theme={theme} size={16}>{u.quizzes}</FigureNum></Cell>
            <Cell>
              <button onClick={() => toggleAdmin(u)} disabled={u.id === currentUserId} style={{
                background: u.is_admin ? theme.accent : "transparent",
                color: u.is_admin ? "#fff" : theme.fg,
                border: `1px solid ${u.is_admin ? theme.accent : theme.rule}`,
                padding: "4px 10px", cursor: u.id === currentUserId ? "default" : "pointer",
                fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.1em",
                opacity: u.id === currentUserId ? 0.5 : 1,
              }}>{u.is_admin ? "ADMIN" : "USER"}</button>
            </Cell>
            <Cell><span style={{ fontFamily: theme.fonts.mono, fontSize: 11, color: theme.fgDim }}>{formatDate(u.created_at)}</span></Cell>
            <Cell>
              {u.id !== currentUserId && (
                <button onClick={() => remove(u)} style={dangerBtnStyle(theme)}>verwijder</button>
              )}
            </Cell>
          </Row>
        ))}
      </Table>
    </div>
  );
}

function QuizzesTab({ theme }) {
  const [quizzes, setQuizzes] = useStateAdmin(null);
  const [error, setError] = useStateAdmin(null);
  const [filter, setFilter] = useStateAdmin("all"); // all | library | draft

  const reload = () =>
    window.kwistApi.get("/api/admin/quizzes").then((r) => setQuizzes(r.quizzes)).catch((e) => setError(e.message));
  useEffectAdmin(() => { reload(); }, []);

  const toggleLibrary = async (q) => {
    await window.kwistApi.patch(`/api/admin/quizzes/${q.id}`, { library: !q.library });
    reload();
  };

  const toggleDraft = async (q) => {
    await window.kwistApi.patch(`/api/admin/quizzes/${q.id}`, { draft: !q.draft });
    reload();
  };

  const publishToLibrary = async (q) => {
    // In één keer: publiceren (draft=false) + in bibliotheek zetten
    await window.kwistApi.patch(`/api/admin/quizzes/${q.id}`, { library: true, draft: false });
    reload();
  };

  const remove = async (q) => {
    const ok = await window.kwistDialog.confirm(
      `Verwijder quiz "${q.title}"?`,
      { title: "Quiz verwijderen?", danger: true, confirmLabel: "Verwijder" }
    );
    if (!ok) return;
    await window.kwistApi.del(`/api/admin/quizzes/${q.id}`);
    reload();
  };

  if (error) return <ErrorBox theme={theme} message={error} />;
  if (!quizzes) return <Loading theme={theme} />;

  const filtered = quizzes.filter((q) => {
    if (filter === "library") return q.library;
    if (filter === "draft") return q.draft;
    return true;
  });
  const libraryCount = quizzes.filter((q) => q.library).length;

  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 24 }}>
        <div>
          <Display theme={theme} size={48} style={{ marginBottom: 8 }}>Quizzes</Display>
          <Eyebrow theme={theme}>── {quizzes.length} STUKS · {libraryCount} IN BIBLIOTHEEK</Eyebrow>
        </div>
        <div style={{ display: "flex", gap: 4 }}>
          {[
            { id: "all", label: "Alle" },
            { id: "library", label: "Bibliotheek" },
            { id: "draft", label: "Concepten" },
          ].map((f) => (
            <button key={f.id} onClick={() => setFilter(f.id)} style={{
              padding: "6px 14px",
              background: filter === f.id ? theme.fg : "transparent",
              color: filter === f.id ? theme.bg : theme.fg,
              border: `1px solid ${filter === f.id ? theme.fg : theme.rule}`,
              cursor: "pointer",
              fontFamily: theme.fonts.display, fontSize: 14,
            }}>{f.label}</button>
          ))}
        </div>
      </div>
      <Table theme={theme} cols={["Titel", "Eigenaar", "Vragen", "Status", "Bibliotheek", ""]} widths={["1.8fr", "1.2fr", "70px", "100px", "120px", "auto"]}>
        {filtered.map((q) => (
          <Row key={q.id} theme={theme}>
            <Cell>
              <div style={{ fontFamily: theme.fonts.display, fontSize: 16 }}>{q.title}</div>
              {q.subtitle && <div style={{ fontSize: 12, color: theme.fgDim }}>{q.subtitle}</div>}
            </Cell>
            <Cell>
              <div>{q.owner?.name || "—"}</div>
              <div style={{ fontFamily: theme.fonts.mono, fontSize: 11, color: theme.fgDim }}>{q.owner?.email}</div>
            </Cell>
            <Cell><FigureNum theme={theme} size={16}>{q.questions}</FigureNum></Cell>
            <Cell>
              <button onClick={() => toggleDraft(q)} style={{
                background: q.draft ? "transparent" : theme.accent,
                color: q.draft ? theme.fgDim : "#fff",
                border: `1px solid ${q.draft ? theme.rule : theme.accent}`,
                padding: "4px 10px", cursor: "pointer",
                fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.1em",
              }}>{q.draft ? "CONCEPT" : "LIVE"}</button>
            </Cell>
            <Cell>
              {q.library ? (
                <button onClick={() => toggleLibrary(q)} style={{
                  background: theme.accent, color: "#fff",
                  border: `1px solid ${theme.accent}`,
                  padding: "4px 10px", cursor: "pointer",
                  fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.1em",
                }}>IN BIEB</button>
              ) : (
                <button onClick={() => publishToLibrary(q)} style={{
                  background: "transparent", color: theme.fgDim,
                  border: `1px solid ${theme.rule}`,
                  padding: "4px 10px", cursor: "pointer",
                  fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.1em",
                }}>+ PUBLICEER</button>
              )}
            </Cell>
            <Cell><button onClick={() => remove(q)} style={dangerBtnStyle(theme)}>verwijder</button></Cell>
          </Row>
        ))}
      </Table>
    </div>
  );
}

function SessionsTab({ theme }) {
  const [sessions, setSessions] = useStateAdmin(null);
  const [error, setError] = useStateAdmin(null);

  const reload = () =>
    window.kwistApi.get("/api/admin/sessions").then((r) => setSessions(r.sessions)).catch((e) => setError(e.message));
  useEffectAdmin(() => { reload(); }, []);

  const end = async (s) => {
    const ok = await window.kwistDialog.confirm(
      `Sessie ${s.code} verwijderen?`,
      { title: "Sessie verwijderen?", danger: true, confirmLabel: "Verwijder" }
    );
    if (!ok) return;
    await window.kwistApi.del(`/api/admin/sessions/${s.id}`);
    reload();
  };

  if (error) return <ErrorBox theme={theme} message={error} />;
  if (!sessions) return <Loading theme={theme} />;

  const statusColor = (s) =>
    s === "running" ? theme.accent :
    s === "lobby" ? theme.fg :
    theme.fgDim;

  const exportCsv = async () => {
    // Token zit in localStorage onder kwist.token; fetch met header voor download.
    const token = window.kwistApi.getToken();
    const res = await fetch("/api/admin/sessions/events.csv", {
      headers: token ? { authorization: `Bearer ${token}` } : {},
    });
    if (!res.ok) {
      const err = await res.text();
      window.kwistDialog?.confirm?.(`Export mislukt: ${err}`, { title: "Fout" });
      return;
    }
    const blob = await res.blob();
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `sessions-events-${new Date().toISOString().slice(0,10)}.csv`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 24 }}>
        <div>
          <Display theme={theme} size={48} style={{ marginBottom: 8 }}>Sessies</Display>
          <Eyebrow theme={theme}>── ZIE WAT ER NU LIVE STAAT</Eyebrow>
        </div>
        <button onClick={exportCsv} style={{
          background: "transparent", color: theme.fg,
          border: `2px solid ${theme.fg}`, padding: "10px 18px",
          fontFamily: theme.fonts.display, fontSize: 13, cursor: "pointer",
          letterSpacing: "0.04em", textTransform: "uppercase",
        }}>↓ Exporteer events (CSV)</button>
      </div>
      <Table theme={theme} cols={["Code", "Quiz", "Host", "Spelers", "Status", "Gestart", ""]} widths={["100px", "1.6fr", "1.2fr", "80px", "100px", "1fr", "auto"]}>
        {sessions.map((s) => (
          <Row key={s.id} theme={theme}>
            <Cell><span style={{ fontFamily: theme.fonts.display, fontSize: 18 }}>{s.code}</span></Cell>
            <Cell>{s.quiz_title}</Cell>
            <Cell><span style={{ fontFamily: theme.fonts.mono, fontSize: 12 }}>{s.host_email}</span></Cell>
            <Cell><FigureNum theme={theme} size={16}>{s.player_count}</FigureNum></Cell>
            <Cell><Eyebrow theme={theme} style={{ color: statusColor(s.status) }}>{s.status.toUpperCase()}</Eyebrow></Cell>
            <Cell><span style={{ fontFamily: theme.fonts.mono, fontSize: 11, color: theme.fgDim }}>{formatDate(s.started_at || s.created_at)}</span></Cell>
            <Cell><button onClick={() => end(s)} style={dangerBtnStyle(theme)}>verwijder</button></Cell>
          </Row>
        ))}
      </Table>
    </div>
  );
}

function FeaturesTab({ theme }) {
  const [features, setFeatures] = useStateAdmin(null);
  const [error, setError] = useStateAdmin(null);
  const [saving, setSaving] = useStateAdmin(null);

  const reload = () =>
    window.kwistApi.get("/api/admin/features").then((r) => setFeatures(r.features)).catch((e) => setError(e.message));
  useEffectAdmin(() => { reload(); }, []);

  const toggle = async (f) => {
    setSaving(f.key);
    try {
      await window.kwistApi.patch(`/api/admin/features/${encodeURIComponent(f.key)}`, { enabled: !f.enabled });
      await reload();
    } catch (e) {
      setError(e.message);
    } finally {
      setSaving(null);
    }
  };

  if (error) return <ErrorBox theme={theme} message={error} />;
  if (!features) return <Loading theme={theme} />;

  return (
    <div>
      <Display theme={theme} size={48} style={{ marginBottom: 8 }}>Capabilities</Display>
      <Eyebrow theme={theme} style={{ marginBottom: 24 }}>── ZET FUNCTIONALITEIT AAN OF UIT VOOR HET HELE PLATFORM</Eyebrow>
      <div style={{ border: `1px solid ${theme.rule}` }}>
        {features.map((f, i) => (
          <div key={f.key} style={{
            display: "grid",
            gridTemplateColumns: "1fr auto",
            gap: 24,
            padding: "16px 20px",
            borderBottom: i < features.length - 1 ? `1px solid ${theme.rule}` : "none",
            alignItems: "center",
          }}>
            <div>
              <div style={{ fontFamily: theme.fonts.display, fontSize: 18 }}>{f.label}</div>
              {f.description && <div style={{ fontSize: 13, color: theme.fgDim, marginTop: 2 }}>{f.description}</div>}
              <div style={{ fontFamily: theme.fonts.mono, fontSize: 10, color: theme.fgDim, marginTop: 4, letterSpacing: "0.05em" }}>
                key: <code>{f.key}</code>
              </div>
            </div>
            <button onClick={() => toggle(f)} disabled={saving === f.key} style={{
              cursor: "pointer",
              border: `1px solid ${f.enabled ? theme.accent : theme.rule}`,
              background: f.enabled ? theme.accent : "transparent",
              color: f.enabled ? "#fff" : theme.fg,
              padding: "8px 18px",
              fontFamily: theme.fonts.display,
              fontSize: 14,
              minWidth: 90,
              opacity: saving === f.key ? 0.6 : 1,
            }}>
              {f.enabled ? "AAN" : "UIT"}
            </button>
          </div>
        ))}
      </div>
      <div style={{ marginTop: 16, fontFamily: theme.fonts.mono, fontSize: 11, color: theme.fgDim, letterSpacing: "0.05em" }}>
        Wijzigingen zijn direct actief — bij volgende page-load voor alle bezoekers zichtbaar.
      </div>
    </div>
  );
}

function TextsTab({ theme, onSiteTextChange }) {
  const [draft, setDraft] = useStateAdmin(null);
  const [original, setOriginal] = useStateAdmin(null);
  const [error, setError] = useStateAdmin(null);
  const [saved, setSaved] = useStateAdmin(false);
  const [saving, setSaving] = useStateAdmin(false);

  useEffectAdmin(() => {
    window.kwistApi.get("/api/admin/site-settings").then((r) => {
      const obj = {};
      for (const row of r.settings) obj[row.key] = row.value;
      setDraft(obj); setOriginal(obj);
    }).catch((e) => setError(e.message));
  }, []);

  const save = async () => {
    if (saving) return;
    setSaving(true); setSaved(false); setError(null);
    try {
      const r = await window.kwistApi.put("/api/admin/site-settings", draft);
      const obj = {};
      for (const row of r.settings) obj[row.key] = row.value;
      setOriginal(obj);
      setDraft(obj);
      setSaved(true);
      onSiteTextChange?.(obj);
    } catch (e) {
      setError(e.message);
    } finally {
      setSaving(false);
    }
  };

  if (error) return <ErrorBox theme={theme} message={error} />;
  if (!draft) return <Loading theme={theme} />;

  const fields = [
    { key: "headerLeft", label: "Header — links", hint: "Verschijnt in de top-strip naast de datum." },
    { key: "headerRight", label: "Header — rechts", hint: "Bv. de huidige editie / versie." },
    { key: "loginTagline", label: "Login — tagline", hint: "De inline-zin onder de eyebrow op het login-scherm." },
    { key: "loginFooterLeft", label: "Login footer — links", hint: "Bv. EST. MMXXIV — ANTWERPEN" },
    { key: "loginFooterCenter", label: "Login footer — midden", hint: "Bv. — PAGINA 01 —" },
    { key: "loginFooterRight", label: "Login footer — rechts", hint: "Bv. VOORWOORD" },
    { key: "loginTerms", label: "Login — voorwaarden-tekst", hint: "Onderaan het formulier." },
    { key: "appFooter", label: "App-brede footer", hint: "Optioneel — gereserveerd voor toekomstig gebruik." },
  ];

  const dirty = Object.keys(draft).some((k) => draft[k] !== original[k]) ||
                Object.keys(original).some((k) => !(k in draft));

  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 24 }}>
        <div>
          <Display theme={theme} size={48} style={{ marginBottom: 8 }}>Footer-teksten</Display>
          <Eyebrow theme={theme}>── HEADER- EN FOOTER-COPY OP HET PLATFORM</Eyebrow>
        </div>
        <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
          {saved && <Eyebrow theme={theme} style={{ color: theme.accent }}>✓ OPGESLAGEN</Eyebrow>}
          <Btn theme={theme} onClick={save} disabled={!dirty || saving} style={{ opacity: (!dirty || saving) ? 0.5 : 1 }}>
            {saving ? "Opslaan…" : "Opslaan"}
          </Btn>
        </div>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 32, columnGap: 56 }}>
        {fields.map((f) => (
          <div key={f.key}>
            <Field
              theme={theme}
              label={`── ${f.label}`}
              value={draft[f.key] ?? ""}
              onChange={(v) => setDraft({ ...draft, [f.key]: v })}
            />
            <div style={{ marginTop: 4, fontFamily: theme.fonts.mono, fontSize: 10, color: theme.fgDim, letterSpacing: "0.05em" }}>
              {f.hint} · key: <code>{f.key}</code>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function DauMauBars({ theme, rows, valueKey, labelKey, labelFn, barColor }) {
  const max = Math.max(...rows.map((r) => r[valueKey]), 1);
  // Toon labels niet voor elke bar als het er veel zijn — eens per ~7 voor DAU.
  const stride = rows.length > 30 ? Math.ceil(rows.length / 8) : 1;
  return (
    <div style={{ border: `1px solid ${theme.rule}`, padding: "20px 24px" }}>
      <div style={{ display: "flex", alignItems: "end", gap: rows.length > 30 ? 2 : 6, height: 120 }}>
        {rows.map((r, i) => (
          <div key={r[labelKey]} title={`${r[labelKey]}: ${r[valueKey]}`}
            style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
            {(rows.length <= 30 || i % stride === 0) && (
              <FigureNum theme={theme} size={11}>{r[valueKey]}</FigureNum>
            )}
            <div style={{
              width: "100%", background: barColor,
              height: `${(r[valueKey] / max) * 80}px`, minHeight: r[valueKey] > 0 ? 3 : 1,
              opacity: r[valueKey] > 0 ? 1 : 0.25,
              transition: "height .3s",
            }} />
            {(rows.length <= 30 || i % stride === 0 || i === rows.length - 1) && (
              <span style={{ fontFamily: theme.fonts.mono, fontSize: 9, color: theme.fgDim, letterSpacing: "0.05em" }}>
                {labelFn(r[labelKey])}
              </span>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

function UsageTab({ theme }) {
  const [data, setData] = useStateAdmin(null);
  const [dauMau, setDauMau] = useStateAdmin(null);
  const [error, setError] = useStateAdmin(null);

  useEffectAdmin(() => {
    window.kwistApi.get("/api/admin/usage-stats").then(setData).catch((e) => setError(e.message));
    window.kwistApi.get("/api/admin/dau-mau").then(setDauMau).catch(() => { /* niet-fataal */ });
  }, []);

  if (error) return <ErrorBox theme={theme} message={error} />;
  if (!data) return <Loading theme={theme} />;

  const maxSessions = Math.max(...(data.sessionsPerMonth.map((r) => r.count)), 1);
  const maxRegs = Math.max(...(data.registrationsPerMonth.map((r) => r.count)), 1);

  const monthLabel = (ym) => {
    const [, m] = ym.split("-");
    return ["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"][parseInt(m, 10) - 1] || m;
  };

  const statusMap = {};
  for (const r of data.sessionsByStatus) statusMap[r.status] = r.count;

  return (
    <div>
      <Display theme={theme} size={56} style={{ marginBottom: 8 }}>Gebruik</Display>
      <Eyebrow theme={theme} style={{ marginBottom: 28 }}>── STATISTIEKEN OVER HET PLATFORMGEBRUIK</Eyebrow>

      {/* KPI tiles */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 0, border: `1px solid ${theme.rule}`, marginBottom: 32 }}>
        {[
          ["Actieve hosts (7d)", data.activeUsers7d],
          ["Actieve hosts (30d)", data.activeUsers30d],
          ["Gem. spelers / sessie", data.avgPlayersPerSession || "—"],
          ["Sessies actief", (statusMap.lobby || 0) + (statusMap.running || 0)],
        ].map(([k, v], i) => (
          <div key={k} style={{
            padding: "20px 20px",
            borderRight: i < 3 ? `1px solid ${theme.rule}` : "none",
          }}>
            <Eyebrow theme={theme}>{k}</Eyebrow>
            <FigureNum theme={theme} size={42} accent>{v}</FigureNum>
          </div>
        ))}
      </div>

      {/* DAU/MAU (ADM-20) */}
      {dauMau && (
        <>
          <div style={{ marginBottom: 32 }}>
            <Eyebrow theme={theme} style={{ marginBottom: 12 }}>── DAU · DAGELIJKS ACTIEVE HOSTS (LAATSTE 60 DAGEN)</Eyebrow>
            <DauMauBars theme={theme} rows={dauMau.dau} valueKey="active_users" labelKey="day"
              labelFn={(s) => s.slice(8, 10)}
              barColor={theme.accent} />
          </div>
          <div style={{ marginBottom: 32 }}>
            <Eyebrow theme={theme} style={{ marginBottom: 12 }}>── MAU · MAANDELIJKS ACTIEVE HOSTS (LAATSTE 12 MAANDEN)</Eyebrow>
            <DauMauBars theme={theme} rows={dauMau.mau} valueKey="active_users" labelKey="month"
              labelFn={(ym) => monthLabel(ym)}
              barColor={theme.fg} />
          </div>
        </>
      )}

      {/* Sessions per month */}
      <div style={{ marginBottom: 32 }}>
        <Eyebrow theme={theme} style={{ marginBottom: 12 }}>── SESSIES PER MAAND (LAATSTE 12 MAANDEN)</Eyebrow>
        {data.sessionsPerMonth.length === 0 ? (
          <div style={{ padding: 24, border: `1px dashed ${theme.rule}`, textAlign: "center" }}>
            <Eyebrow theme={theme}>NOG GEEN DATA</Eyebrow>
          </div>
        ) : (
          <div style={{ border: `1px solid ${theme.rule}`, padding: "20px 24px" }}>
            <div style={{ display: "flex", alignItems: "end", gap: 6, height: 120 }}>
              {data.sessionsPerMonth.map((r) => (
                <div key={r.month} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
                  <FigureNum theme={theme} size={12}>{r.count}</FigureNum>
                  <div style={{
                    width: "100%", background: theme.accent,
                    height: `${(r.count / maxSessions) * 80}px`, minHeight: 3,
                    transition: "height .3s",
                  }} />
                  <span style={{ fontFamily: theme.fonts.mono, fontSize: 9, color: theme.fgDim, letterSpacing: "0.05em" }}>
                    {monthLabel(r.month)}
                  </span>
                </div>
              ))}
            </div>
          </div>
        )}
      </div>

      {/* Registrations per month */}
      <div style={{ marginBottom: 32 }}>
        <Eyebrow theme={theme} style={{ marginBottom: 12 }}>── REGISTRATIES PER MAAND</Eyebrow>
        {data.registrationsPerMonth.length === 0 ? (
          <div style={{ padding: 24, border: `1px dashed ${theme.rule}`, textAlign: "center" }}>
            <Eyebrow theme={theme}>NOG GEEN DATA</Eyebrow>
          </div>
        ) : (
          <div style={{ border: `1px solid ${theme.rule}`, padding: "20px 24px" }}>
            <div style={{ display: "flex", alignItems: "end", gap: 6, height: 120 }}>
              {data.registrationsPerMonth.map((r) => (
                <div key={r.month} style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", gap: 4 }}>
                  <FigureNum theme={theme} size={12}>{r.count}</FigureNum>
                  <div style={{
                    width: "100%", background: theme.fg,
                    height: `${(r.count / maxRegs) * 80}px`, minHeight: 3,
                    transition: "height .3s",
                  }} />
                  <span style={{ fontFamily: theme.fonts.mono, fontSize: 9, color: theme.fgDim, letterSpacing: "0.05em" }}>
                    {monthLabel(r.month)}
                  </span>
                </div>
              ))}
            </div>
          </div>
        )}
      </div>

      {/* Session status breakdown */}
      <div style={{ marginBottom: 32 }}>
        <Eyebrow theme={theme} style={{ marginBottom: 12 }}>── SESSIES NAAR STATUS</Eyebrow>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 0, border: `1px solid ${theme.rule}` }}>
          {[
            ["Lobby", statusMap.lobby || 0],
            ["Actief", statusMap.running || 0],
            ["Afgelopen", statusMap.finished || 0],
          ].map(([k, v], i) => (
            <div key={k} style={{
              padding: "16px 20px",
              borderRight: i < 2 ? `1px solid ${theme.rule}` : "none",
            }}>
              <Eyebrow theme={theme}>{k}</Eyebrow>
              <FigureNum theme={theme} size={36} accent>{v}</FigureNum>
            </div>
          ))}
        </div>
      </div>

      {/* Top quizzes */}
      <div>
        <Eyebrow theme={theme} style={{ marginBottom: 12 }}>── MEEST GESPEELDE QUIZZES</Eyebrow>
        {data.topQuizzes.length === 0 ? (
          <div style={{ padding: 24, border: `1px dashed ${theme.rule}`, textAlign: "center" }}>
            <Eyebrow theme={theme}>NOG GEEN QUIZZES</Eyebrow>
          </div>
        ) : (
          <div style={{ border: `1px solid ${theme.rule}` }}>
            {data.topQuizzes.map((q, i) => (
              <div key={q.id} style={{
                display: "grid", gridTemplateColumns: "40px 36px 1fr 100px 80px",
                gap: 12, padding: "12px 16px", alignItems: "center",
                borderBottom: i < data.topQuizzes.length - 1 ? `1px solid ${theme.rule}` : "none",
              }}>
                <FigureNum theme={theme} size={22}>{("0" + (i + 1)).slice(-2)}</FigureNum>
                <div style={{
                  width: 32, height: 32, background: q.color || theme.fg, color: "#fff",
                  display: "grid", placeItems: "center",
                  fontFamily: theme.fonts.display, fontSize: 18,
                }}>{q.glyph || "♣"}</div>
                <div style={{ fontFamily: theme.fonts.display, fontSize: 18, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {q.title}
                </div>
                <div style={{ textAlign: "right" }}>
                  <FigureNum theme={theme} size={18} accent>{q.plays}</FigureNum>
                  <div style={{ fontFamily: theme.fonts.mono, fontSize: 9, color: theme.fgDim }}>SESSIES</div>
                </div>
                <div style={{ textAlign: "right" }}>
                  <FigureNum theme={theme} size={18}>{q.questions}</FigureNum>
                  <div style={{ fontFamily: theme.fonts.mono, fontSize: 9, color: theme.fgDim }}>VRAGEN</div>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

function BackupTab({ theme }) {
  const [exporting, setExporting] = useStateAdmin(false);
  const [importing, setImporting] = useStateAdmin(false);
  const [pendingFile, setPendingFile] = useStateAdmin(null);
  const [pendingMeta, setPendingMeta] = useStateAdmin(null);
  const [pendingBackup, setPendingBackup] = useStateAdmin(null);
  const [result, setResult] = useStateAdmin(null);
  const [error, setError] = useStateAdmin(null);
  const fileRef = React.useRef(null);

  const downloadBackup = async () => {
    setExporting(true); setError(null);
    try {
      const tok = window.kwistApi.getToken();
      const res = await fetch("/api/admin/backup/export", {
        headers: tok ? { authorization: `Bearer ${tok}` } : {},
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const blob = await res.blob();
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      const stamp = new Date().toISOString().slice(0, 10);
      a.download = `kwisthet-backup-${stamp}.json`;
      document.body.appendChild(a); a.click(); a.remove();
      setTimeout(() => URL.revokeObjectURL(url), 1000);
    } catch (e) {
      setError(e.message);
    } finally {
      setExporting(false);
    }
  };

  const handleFile = async (file) => {
    if (!file) return;
    setError(null); setResult(null);
    try {
      const text = await file.text();
      const data = JSON.parse(text);
      if (data.kind !== "kwisthet-backup") {
        throw new Error("Dit is geen geldig KwistHet backup-bestand.");
      }
      setPendingFile(file);
      setPendingBackup(data);
      setPendingMeta({
        exportedAt: data.exportedAt,
        users: data.counts?.users ?? data.users?.length ?? 0,
        features: data.counts?.features ?? data.features?.length ?? 0,
        siteSettings: data.counts?.siteSettings ?? data.siteSettings?.length ?? 0,
        quizzes: data.counts?.quizzes ?? data.quizzes?.length ?? 0,
        questions: data.counts?.questions ?? 0,
      });
    } catch (e) {
      setError("Kon bestand niet lezen: " + e.message);
    }
  };

  const cancelImport = () => {
    setPendingFile(null); setPendingMeta(null); setPendingBackup(null);
    if (fileRef.current) fileRef.current.value = "";
  };

  const confirmImport = async () => {
    if (!pendingBackup) return;
    setImporting(true); setError(null); setResult(null);
    try {
      const r = await window.kwistApi.post("/api/admin/backup/import", pendingBackup);
      setResult(r.stats);
      cancelImport();
    } catch (e) {
      setError(e.message);
    } finally {
      setImporting(false);
    }
  };

  return (
    <div>
      <Display theme={theme} size={56} style={{ marginBottom: 8 }}>Backup</Display>
      <Eyebrow theme={theme} style={{ marginBottom: 28 }}>── EXPORTEER OF HERSTEL EEN VOLLEDIGE KOPIE</Eyebrow>

      {/* Export */}
      <section style={{ border: `1px solid ${theme.rule}`, padding: "24px 28px", marginBottom: 24 }}>
        <Eyebrow theme={theme} style={{ marginBottom: 12 }}>── EXPORTEREN</Eyebrow>
        <p style={{ fontSize: 14, lineHeight: 1.6, color: theme.fgDim, margin: "0 0 20px 0", maxWidth: 640 }}>
          Download een JSON-bestand met alle gebruikers (incl. wachtwoord-hashes en MFA-instellingen),
          feature flags, site-teksten en quizzes met al hun vragen. Sessies, spelers en antwoorden
          worden niet meegenomen — die zijn vluchtig.
        </p>
        <Btn theme={theme} onClick={downloadBackup} disabled={exporting}>
          {exporting ? "Bezig…" : "↧ Download backup-bestand"}
        </Btn>
      </section>

      {/* Import */}
      <section style={{ border: `1px solid ${theme.rule}`, padding: "24px 28px" }}>
        <Eyebrow theme={theme} style={{ marginBottom: 12 }}>── IMPORTEREN</Eyebrow>
        <p style={{ fontSize: 14, lineHeight: 1.6, color: theme.fgDim, margin: "0 0 20px 0", maxWidth: 640 }}>
          Upload een eerder geëxporteerd bestand. Bestaande data wordt <strong>samengevoegd</strong>:
          gebruikers worden gematcht op e-mail, quizzes op id, feature flags en teksten op key.
          Vragen van bestaande quizzes worden vervangen door de versie uit het bestand.
        </p>

        {error && (
          <div style={{
            marginBottom: 16, padding: "10px 14px",
            border: `1px solid ${theme.accent}`, background: `${theme.accent}10`,
            color: theme.accent, fontFamily: theme.fonts.mono, fontSize: 12,
          }}>{error}</div>
        )}

        {!pendingMeta && (
          <>
            <input
              ref={fileRef} type="file" accept=".json,application/json"
              style={{ display: "none" }}
              onChange={(e) => handleFile(e.target.files?.[0])}
            />
            <Btn theme={theme} variant="outline" onClick={() => fileRef.current?.click()}>
              Kies backup-bestand…
            </Btn>
          </>
        )}

        {pendingMeta && (
          <div style={{ border: `1px dashed ${theme.rule}`, padding: "20px 24px", background: theme.bg2 }}>
            <Eyebrow theme={theme} style={{ marginBottom: 14, color: theme.accent }}>── KLAAR OM TE IMPORTEREN</Eyebrow>
            <div style={{ fontFamily: theme.fonts.mono, fontSize: 12, color: theme.fgDim, marginBottom: 4 }}>
              Bestand: <code>{pendingFile?.name}</code>
            </div>
            <div style={{ fontFamily: theme.fonts.mono, fontSize: 12, color: theme.fgDim, marginBottom: 16 }}>
              Geëxporteerd: {pendingMeta.exportedAt ? new Date(pendingMeta.exportedAt).toLocaleString("nl-NL") : "onbekend"}
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 0, border: `1px solid ${theme.rule}`, marginBottom: 20 }}>
              {[
                ["Gebruikers", pendingMeta.users],
                ["Features", pendingMeta.features],
                ["Site-teksten", pendingMeta.siteSettings],
                ["Quizzes", pendingMeta.quizzes],
                ["Vragen", pendingMeta.questions],
              ].map(([k, v], i) => (
                <div key={k} style={{
                  padding: "12px 14px",
                  borderRight: i < 4 ? `1px solid ${theme.rule}` : "none",
                }}>
                  <Eyebrow theme={theme}>{k}</Eyebrow>
                  <FigureNum theme={theme} size={26} accent>{v}</FigureNum>
                </div>
              ))}
            </div>
            <div style={{ display: "flex", gap: 12 }}>
              <Btn theme={theme} onClick={confirmImport} disabled={importing}>
                {importing ? "Bezig met importeren…" : "↥ Bevestig import"}
              </Btn>
              <Btn theme={theme} variant="ghost" onClick={cancelImport} disabled={importing}>
                Annuleren
              </Btn>
            </div>
          </div>
        )}

        {result && (
          <div style={{ marginTop: 20, border: `1px solid ${theme.accent}`, padding: "16px 20px", background: `${theme.accent}10` }}>
            <Eyebrow theme={theme} style={{ color: theme.accent, marginBottom: 12 }}>── ✓ IMPORT VOLTOOID</Eyebrow>
            <div style={{ fontFamily: theme.fonts.mono, fontSize: 12, lineHeight: 1.7, color: theme.fg }}>
              <div>Gebruikers: <strong>{result.users.inserted}</strong> nieuw, <strong>{result.users.updated}</strong> bijgewerkt</div>
              <div>Features: <strong>{result.features}</strong> verwerkt</div>
              <div>Site-teksten: <strong>{result.siteSettings}</strong> verwerkt</div>
              <div>Quizzes: <strong>{result.quizzes.inserted}</strong> nieuw, <strong>{result.quizzes.updated}</strong> bijgewerkt, <strong>{result.quizzes.skipped}</strong> overgeslagen</div>
              <div>Vragen: <strong>{result.questions}</strong> ingelezen</div>
            </div>
          </div>
        )}
      </section>
    </div>
  );
}

function BrandingTab({ theme, onBrandingChange }) {
  const current = theme.branding || "brut";
  const brandings = window.BRANDINGS || {};
  const keys = Object.keys(brandings);

  return (
    <div>
      <Display theme={theme} size={48} style={{ marginBottom: 8 }}>Branding</Display>
      <Eyebrow theme={theme} style={{ marginBottom: 28 }}>── WISSEL TUSSEN VISUELE STIJLEN OM TE TESTEN</Eyebrow>

      <div style={{ display: "grid", gridTemplateColumns: `repeat(${keys.length}, 1fr)`, gap: 24 }}>
        {keys.map((key) => {
          const b = brandings[key];
          const active = current === key;
          const previewFonts = window.FONT_PAIRINGS?.[b.fontPairing] || {};
          return (
            <div key={key} onClick={() => !active && onBrandingChange?.(key)} style={{
              border: active ? `3px solid ${theme.accent}` : `1px solid ${theme.rule}`,
              borderRadius: b.radius,
              padding: 0,
              cursor: active ? "default" : "pointer",
              overflow: "hidden",
              transition: "border-color .15s",
            }}>
              {/* Preview card */}
              <div style={{
                background: b.tones.paper,
                padding: "28px 24px 20px",
                borderBottom: `${b.borderWidth}px solid ${b.radius ? "#d0cec9" : "#0a0a0a"}`,
              }}>
                <div style={{
                  fontFamily: previewFonts.display || "sans-serif",
                  fontSize: 32,
                  fontWeight: b.fontWeight,
                  letterSpacing: b.letterSpacing,
                  textTransform: b.textTransform,
                  lineHeight: 1,
                  marginBottom: 12,
                  color: "#0a0a0a",
                }}>Kwist het!</div>
                <div style={{
                  display: "inline-block",
                  background: b.accent,
                  color: "#fff",
                  padding: b.radius ? "8px 20px" : "8px 16px",
                  borderRadius: b.radius * 0.7,
                  border: b.radius ? "none" : `2px solid #0a0a0a`,
                  boxShadow: b.radius ? "0 2px 8px rgba(0,0,0,0.10)" : `4px 4px 0 0 #0a0a0a`,
                  fontFamily: previewFonts.display || "sans-serif",
                  fontWeight: b.fontWeight,
                  fontSize: 14,
                  textTransform: b.textTransform,
                }}>{b.radius ? "Start quiz" : "start quiz"}</div>
                <div style={{
                  marginTop: 14,
                  display: "inline-block",
                  marginLeft: 12,
                  background: b.radius ? "#f3f1ec" : "#ffe14a",
                  padding: "4px 12px",
                  borderRadius: b.radius ? 20 : 0,
                  border: b.radius ? `1.5px solid #d0cec9` : `2px solid #0a0a0a`,
                  fontFamily: previewFonts.mono || "monospace",
                  fontSize: 10, fontWeight: 700,
                  letterSpacing: "0.06em",
                  textTransform: "uppercase",
                  color: "#0a0a0a",
                }}>PREVIEW</div>
              </div>
              {/* Info */}
              <div style={{ padding: "16px 24px 20px", background: theme.bg2 }}>
                <div style={{
                  fontFamily: theme.fonts.display,
                  fontSize: 22, fontWeight: 700,
                  marginBottom: 4,
                }}>{b.label}</div>
                <div style={{
                  fontFamily: theme.fonts.body,
                  fontSize: 13, color: theme.fgDim,
                  lineHeight: 1.5,
                  marginBottom: 12,
                }}>{b.description}</div>
                <div style={{
                  fontFamily: theme.fonts.mono,
                  fontSize: 10, color: theme.fgDim,
                  letterSpacing: "0.08em",
                  marginBottom: 12,
                }}>
                  FONT: {previewFonts.label || b.fontPairing} · RADIUS: {b.radius}px · ACCENT: {b.accent}
                </div>
                {active ? (
                  <span style={{
                    fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.1em",
                    padding: "6px 14px",
                    border: `1px solid ${theme.accent}`,
                    background: theme.accent,
                    color: "#fff",
                  }}>ACTIEF</span>
                ) : (
                  <span style={{
                    fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.1em",
                    padding: "6px 14px",
                    border: `1px solid ${theme.rule}`,
                    background: "transparent",
                    color: theme.fgDim,
                  }}>ACTIVEREN</span>
                )}
              </div>
            </div>
          );
        })}
      </div>

      <div style={{
        marginTop: 20,
        fontFamily: theme.fonts.mono,
        fontSize: 11,
        color: theme.fgDim,
        letterSpacing: "0.05em",
      }}>
        Branding wordt direct toegepast op het hele platform. Ververs de pagina om het volledig effect te zien.
      </div>
    </div>
  );
}

// =================== HELPERS ===================

function Loading({ theme }) {
  return <div style={{ padding: 40, textAlign: "center" }}><Eyebrow theme={theme}>BEZIG MET LADEN…</Eyebrow></div>;
}

function ErrorBox({ theme, message }) {
  return (
    <div style={{
      padding: "14px 18px",
      border: `1px solid ${theme.accent}`,
      background: `${theme.accent}10`,
      color: theme.accent,
      fontFamily: theme.fonts.mono, fontSize: 13,
    }}>{message}</div>
  );
}

function Table({ theme, cols, widths, children }) {
  const grid = widths.join(" ");
  // Forward the grid template down to every Row child via cloneElement.
  const rows = React.Children.map(children, (child) =>
    child && child.type === Row ? React.cloneElement(child, { gridTemplate: grid }) : child
  );
  return (
    <div style={{ border: `1px solid ${theme.rule}` }}>
      <div style={{
        display: "grid", gridTemplateColumns: grid, gap: 12,
        padding: "12px 16px",
        borderBottom: `1px solid ${theme.rule}`,
        background: theme.bg2,
        color: theme.fg,
      }}>
        {cols.map((c, i) => (
          <Eyebrow key={i} theme={theme}>{c}</Eyebrow>
        ))}
      </div>
      <div>{rows}</div>
    </div>
  );
}

function Row({ theme, gridTemplate, children }) {
  return (
    <div style={{
      display: "grid",
      gridTemplateColumns: gridTemplate || "1fr",
      padding: "12px 16px",
      borderBottom: `1px solid ${theme.rule}`,
      alignItems: "center",
      gap: 12,
    }}>{children}</div>
  );
}

function Cell({ children }) {
  return <div style={{ minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{children}</div>;
}

function dangerBtnStyle(theme) {
  return {
    background: "transparent",
    color: theme.accent,
    border: `1px solid ${theme.accent}`,
    padding: "4px 10px", cursor: "pointer",
    fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: "0.1em",
  };
}

function formatDate(s) {
  if (!s) return "—";
  const d = new Date(s);
  return d.toLocaleString("nl-NL", { day: "2-digit", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit" });
}

window.AdminScreen = AdminScreen;
