"use client";

import { useState, useEffect, useRef, useCallback } from "react";

// ─── Types ────────────────────────────────────────────────────────────────────

type NewsItem = { id: string; titel: string; inhalt: string; publishedAt: string; isFeatured: boolean; imageUrl?: string };
type Photo = { id: string; src: string; alt: string; caption?: string; width: number; height: number; order: number };
type VideoItem = { id: string; type: "embed" | "local" | "link"; title: string; description: string; videoId?: string; src?: string; url?: string; label?: string; compact?: boolean; order: number };
type EventItem = { id: string; titel: string; datum: string; datumLabel: string; uhrzeit: string; ort: string; typ: string; beschreibung: string; isPublic: boolean };
type TrainingSession = { id: string; tag: string; startTime: string; endTime: string; gruppe: string; level: string; halle: string; aktiv: boolean; order: number };
type PricingTier = { id: string; bezeichnung: string; beschreibung: string; zeilen: { periode: string; betragChf: number }[]; features: string[]; empfohlen?: boolean; cta: string; order: number };
type TeamMember = { id: string; name: string; rolle: string; grad?: string; bio?: string; imageUrl?: string; isCheftrainer?: boolean; order: number };
type VorstandMember = { id: string; funktion: string; person: string; order: number };
type TeamData = { trainer: TeamMember[]; vorstand: VorstandMember[]; mitglieder: string[] };
type HolidayPeriod = { id: string; label: string; dates: string; note?: string; order: number };
type AuditEntry = { ts: string; ip: string; action: string; detail: string };
type Stats = { news: number; photos: number; videos: number; events: number; nextEvents: EventItem[]; trainingSessions: number; teamMembers: number; holidays: number; contactsUnread: number; mitgliederAktiv: number; security: { totpEnabled: boolean; weakPassword: boolean }; recentAudit: AuditEntry[] };
type InviteTokenStatus = { expiresAt: string; createdAt: string; daysLeft: number; lastCronCheck: string | null; warningSentAt: string | null; status: "ok" | "warning" | "expired" };
type ContactSubmission = { id: string; name: string; email: string; phone?: string; alterYears?: string; typ: string; nachricht?: string; submittedAt: string; isRead: boolean; isArchived: boolean };
type Mitglied = { id: string; name: string; email?: string; phone?: string; geburtsdatum?: string; eintrittsdatum: string; gürtelgrad: string; aktiv: boolean; notizen?: string; imageUrl?: string };
type Dokument = { id: string; titel: string; beschreibung?: string; src: string; dateiname: string; kategorie: string; oeffentlich: boolean; uploadedAt: string; order: number };
type PruefungsErgebnis = { mitgliedId: string; mitgliedName: string; vorherGrad: string; nachherGrad: string; bestanden: boolean; notizen?: string };
type Pruefung = { id: string; datum: string; ort: string; prüfer?: string; ergebnisse: PruefungsErgebnis[]; autoNewsId?: string };

// ─── Helpers ─────────────────────────────────────────────────────────────────

async function apiFetch(url: string, opts?: RequestInit) {
  const res = await fetch(url, { credentials: "include", ...opts });
  if (!res.ok) { const d = await res.json().catch(() => ({})); throw new Error(d.error ?? res.statusText); }
  return res.json();
}
function fmtDate(iso: string) { return new Date(iso).toLocaleDateString("de-CH", { day: "2-digit", month: "short", year: "numeric" }); }
function newId() { return Date.now().toString(); }

// ─── Styles ──────────────────────────────────────────────────────────────────

const S = {
  page: { minHeight: "100vh", background: "#0f0f0f", color: "#e8e4df", fontFamily: "system-ui,-apple-system,sans-serif" } as React.CSSProperties,
  header: { background: "#1a1a1a", borderBottom: "1px solid #2a2a2a", padding: "0 24px", height: 60, display: "flex", alignItems: "center", justifyContent: "space-between", position: "sticky" as const, top: 0, zIndex: 50 },
  logo: { fontSize: 18, fontWeight: 700, color: "#e8e4df", letterSpacing: "0.04em" },
  badge: { background: "#8B0000", color: "#fff", fontSize: 11, padding: "2px 8px", borderRadius: 4, marginLeft: 10, fontWeight: 600 } as React.CSSProperties,
  badgeOk: { background: "#1a3a1a", color: "#6f6", fontSize: 11, padding: "2px 6px", borderRadius: 4, fontWeight: 600 } as React.CSSProperties,
  badgeWarn: { background: "#3a2a00", color: "#fb0", fontSize: 11, padding: "2px 6px", borderRadius: 4, fontWeight: 600 } as React.CSSProperties,
  badgeDanger: { background: "#3a0000", color: "#f66", fontSize: 11, padding: "2px 6px", borderRadius: 4, fontWeight: 600 } as React.CSSProperties,
  badgeInfo: { background: "#1a2a3a", color: "#7ab", fontSize: 11, padding: "2px 6px", borderRadius: 4, fontWeight: 600 } as React.CSSProperties,
  btn: { background: "#8B0000", color: "#fff", border: "none", padding: "8px 18px", borderRadius: 4, cursor: "pointer", fontSize: 13, fontWeight: 600 } as React.CSSProperties,
  btnSm: { background: "#8B0000", color: "#fff", border: "none", padding: "5px 12px", borderRadius: 4, cursor: "pointer", fontSize: 12, fontWeight: 600 } as React.CSSProperties,
  btnGhost: { background: "transparent", color: "#8a8680", border: "1px solid #2a2a2a", padding: "5px 12px", borderRadius: 4, cursor: "pointer", fontSize: 12 } as React.CSSProperties,
  btnDanger: { background: "#3b0000", color: "#f88", border: "none", padding: "5px 12px", borderRadius: 4, cursor: "pointer", fontSize: 12 } as React.CSSProperties,
  btnLogout: { background: "transparent", color: "#8a8680", border: "1px solid #2a2a2a", padding: "6px 14px", borderRadius: 4, cursor: "pointer", fontSize: 13 } as React.CSSProperties,
  tabs: { display: "flex", gap: 2, padding: "12px 24px 0", borderBottom: "1px solid #2a2a2a", background: "#111", overflowX: "auto" as const, WebkitOverflowScrolling: "touch" } as React.CSSProperties,
  tab: (active: boolean): React.CSSProperties => ({ padding: "8px 14px", borderRadius: "6px 6px 0 0", border: "none", background: active ? "#1a1a1a" : "transparent", color: active ? "#e8e4df" : "#8a8680", cursor: "pointer", fontSize: 13, fontWeight: active ? 600 : 400, borderBottom: active ? "2px solid #8B0000" : "2px solid transparent", whiteSpace: "nowrap" as const }),
  content: { padding: "24px", maxWidth: 940, margin: "0 auto" },
  card: { background: "#1a1a1a", border: "1px solid #2a2a2a", borderRadius: 8, padding: 16, marginBottom: 12 } as React.CSSProperties,
  secCard: { background: "#141414", border: "1px solid #2a2a2a", borderRadius: 8, padding: 20, marginBottom: 16 } as React.CSSProperties,
  input: { background: "#0f0f0f", border: "1px solid #2a2a2a", borderRadius: 4, color: "#e8e4df", padding: "8px 12px", fontSize: 14, width: "100%", boxSizing: "border-box" as const },
  textarea: { background: "#0f0f0f", border: "1px solid #2a2a2a", borderRadius: 4, color: "#e8e4df", padding: "8px 12px", fontSize: 14, width: "100%", boxSizing: "border-box" as const, minHeight: 100, resize: "vertical" as const, fontFamily: "inherit" },
  select: { background: "#0f0f0f", border: "1px solid #2a2a2a", borderRadius: 4, color: "#e8e4df", padding: "8px 12px", fontSize: 14, width: "100%" } as React.CSSProperties,
  label: { display: "block", fontSize: 12, color: "#8a8680", marginBottom: 4, fontWeight: 500 } as React.CSSProperties,
  row: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 8, flexWrap: "wrap" as const } as React.CSSProperties,
  actions: { display: "flex", gap: 6, alignItems: "center", flexShrink: 0 } as React.CSSProperties,
  modal: { position: "fixed" as const, inset: 0, background: "rgba(0,0,0,0.75)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 100, padding: 16 },
  modalBox: { background: "#1a1a1a", border: "1px solid #2a2a2a", borderRadius: 10, padding: 24, width: "100%", maxWidth: 580, maxHeight: "90vh", overflowY: "auto" as const },
  toast: (type: "ok" | "err"): React.CSSProperties => ({ position: "fixed" as const, bottom: 24, right: 24, background: type === "ok" ? "#1a3a1a" : "#3a1a1a", color: type === "ok" ? "#6f6" : "#f88", border: `1px solid ${type === "ok" ? "#2a5a2a" : "#5a2a2a"}`, borderRadius: 6, padding: "10px 18px", fontSize: 13, zIndex: 200, boxShadow: "0 4px 20px rgba(0,0,0,0.4)" }),
  statCard: { background: "#1a1a1a", border: "1px solid #2a2a2a", borderRadius: 8, padding: "16px 20px", display: "flex", flexDirection: "column" as const, gap: 4 },
};

// ─── Toast hook ───────────────────────────────────────────────────────────────

function useToast() {
  const [msg, setMsg] = useState<{ text: string; type: "ok" | "err" } | null>(null);
  const t = useRef<ReturnType<typeof setTimeout>>();
  const show = useCallback((text: string, type: "ok" | "err" = "ok") => {
    setMsg({ text, type });
    clearTimeout(t.current);
    t.current = setTimeout(() => setMsg(null), 4000);
  }, []);
  return { msg, show };
}

// ─── Login ────────────────────────────────────────────────────────────────────

function LoginScreen({ onLogin }: { onLogin: (mustChangePw: boolean) => void }) {
  const [step, setStep] = useState<"password" | "totp">("password");
  const [pw, setPw] = useState(""); const [totp, setTotp] = useState(""); const [err, setErr] = useState(""); const [loading, setLoading] = useState(false);
  async function submit(e: React.FormEvent) {
    e.preventDefault(); setLoading(true); setErr("");
    try {
      const body: Record<string, string> = { password: pw };
      if (step === "totp") body.totp = totp;
      const data = await apiFetch("/api/admin/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
      if (data.needsTotp) { setStep("totp"); setTotp(""); } else { onLogin(!!data.mustChangePassword); }
    } catch (ex: unknown) { setErr(ex instanceof Error ? ex.message : "Fehler"); }
    finally { setLoading(false); }
  }
  return (
    <div style={{ ...S.page, display: "flex", alignItems: "center", justifyContent: "center" }}>
      <div style={{ background: "#1a1a1a", border: "1px solid #2a2a2a", borderRadius: 12, padding: 32, width: "min(380px, calc(100vw - 32px))", textAlign: "center" }}>
        <div style={{ fontSize: 28, marginBottom: 4 }}>🥋</div>
        <h1 style={{ fontSize: 22, fontWeight: 700, marginBottom: 4 }}>Dojo Admin</h1>
        <p style={{ color: "#8a8680", fontSize: 13, marginBottom: 28 }}>JKA-Karateclub Arbon</p>
        <form onSubmit={submit} style={{ textAlign: "left" }}>
          {step === "password" ? (<>
            <label style={S.label}>Passwort</label>
            <input type="password" value={pw} onChange={e => setPw(e.target.value)} style={{ ...S.input, marginBottom: 12 }} autoFocus required />
          </>) : (<>
            <p style={{ fontSize: 13, color: "#8a8680", marginBottom: 12, textAlign: "center" }}>6-stelliger Code aus der Authenticator-App:</p>
            <input type="text" value={totp} onChange={e => setTotp(e.target.value.replace(/\D/g, ""))} maxLength={6} inputMode="numeric" autoComplete="one-time-code" style={{ ...S.input, marginBottom: 12, letterSpacing: "0.3em", fontSize: 22, textAlign: "center" }} autoFocus placeholder="000000" />
            <button type="button" style={{ ...S.btnGhost, marginBottom: 12, width: "100%", textAlign: "center" }} onClick={() => { setStep("password"); setErr(""); }}>← Zurück</button>
          </>)}
          {err && <div style={{ background: "#2a1010", border: "1px solid #5a2020", borderRadius: 4, padding: "8px 12px", marginBottom: 10, fontSize: 12, color: "#f88" }}>{err}</div>}
          <button type="submit" disabled={loading} style={{ ...S.btn, width: "100%", padding: "10px" }}>{loading ? "…" : step === "password" ? "Weiter" : "Anmelden"}</button>
        </form>
      </div>
    </div>
  );
}

// ─── Forced Password Change (shown after first login with default password) ───

function ForcedPasswordChange({ onDone }: { onDone: () => void }) {
  const [form, setForm] = useState({ new: "", confirm: "" });
  const [loading, setLoading] = useState(false);
  const [err, setErr] = useState("");

  const pwStrength = (() => { const p = form.new; if (!p) return null; if (p.length < 8) return { label: "Sehr schwach", color: "#f44" }; if (p.length < 12) return { label: "Schwach (min. 12)", color: "#f84" }; const has = [/[A-Z]/, /[a-z]/, /[0-9]/, /[^A-Za-z0-9]/].filter(r => r.test(p)).length; if (has < 2) return { label: "Mittel", color: "#fb0" }; if (has < 3) return { label: "Gut", color: "#9d0" }; return { label: "Stark", color: "#6f6" }; })();

  async function submit(e: React.FormEvent) {
    e.preventDefault();
    if (form.new !== form.confirm) { setErr("Passwörter stimmen nicht überein"); return; }
    if (form.new.length < 12) { setErr("Mindestens 12 Zeichen erforderlich"); return; }
    setLoading(true); setErr("");
    try {
      await apiFetch("/api/admin/password/force", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ newPassword: form.new, confirmPassword: form.confirm }) });
      onDone();
    } catch (ex: unknown) { setErr(ex instanceof Error ? ex.message : "Fehler"); }
    finally { setLoading(false); }
  }

  return (
    <div style={{ ...S.page, display: "flex", alignItems: "center", justifyContent: "center" }}>
      <div style={{ background: "#1a1a1a", border: "1px solid #8B0000", borderRadius: 12, padding: 40, width: 420 }}>
        <div style={{ fontSize: 28, marginBottom: 8, textAlign: "center" }}>🔒</div>
        <h2 style={{ fontSize: 20, fontWeight: 700, marginBottom: 8, textAlign: "center" }}>Passwort festlegen</h2>
        <div style={{ background: "#2a0000", border: "1px solid #5a1010", borderRadius: 6, padding: "10px 14px", marginBottom: 24, fontSize: 13, color: "#f88", textAlign: "center" }}>
          Das Standard-Passwort ist noch aktiv.<br />Bitte wähle jetzt ein sicheres Passwort um fortzufahren.
        </div>
        {err && <div style={{ background: "#2a1010", border: "1px solid #5a2020", borderRadius: 4, padding: "8px 12px", marginBottom: 12, fontSize: 12, color: "#f88" }}>{err}</div>}
        <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          <div>
            <label style={S.label}>Neues Passwort <span style={{ color: "#555" }}>(min. 12 Zeichen)</span></label>
            <input type="password" value={form.new} onChange={e => setForm(f => ({ ...f, new: e.target.value }))} style={S.input} required minLength={12} autoFocus />
            {pwStrength && <div style={{ fontSize: 11, color: pwStrength.color, marginTop: 4 }}>Stärke: {pwStrength.label}</div>}
          </div>
          <div>
            <label style={S.label}>Wiederholen</label>
            <input type="password" value={form.confirm} onChange={e => setForm(f => ({ ...f, confirm: e.target.value }))} style={S.input} required />
            {form.confirm && form.new !== form.confirm && <div style={{ fontSize: 11, color: "#f88", marginTop: 4 }}>Stimmt nicht überein</div>}
          </div>
          <button type="submit" disabled={loading || form.new !== form.confirm || form.new.length < 12} style={{ ...S.btn, padding: "10px", fontSize: 14 }}>
            {loading ? "Speichern…" : "Passwort festlegen & weiter"}
          </button>
        </form>
      </div>
    </div>
  );
}

// ─── Modal wrapper ────────────────────────────────────────────────────────────

function Modal({ title, onClose, children }: { title: string; onClose: () => void; children: React.ReactNode }) {
  return (
    <div style={S.modal} onClick={onClose}>
      <div style={S.modalBox} onClick={e => e.stopPropagation()}>
        <h2 style={{ marginTop: 0, marginBottom: 20, fontSize: 18 }}>{title}</h2>
        {children}
      </div>
    </div>
  );
}

function FormActions({ loading, onClose, label = "Speichern" }: { loading: boolean; onClose: () => void; label?: string }) {
  return (
    <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 16 }}>
      <button type="button" style={S.btnGhost} onClick={onClose}>Abbrechen</button>
      <button type="submit" disabled={loading} style={S.btn}>{loading ? "…" : label}</button>
    </div>
  );
}

// ─── Overview ─────────────────────────────────────────────────────────────────

function Overview({ onTabChange }: { onTabChange: (t: Tab) => void }) {
  const [stats, setStats] = useState<Stats | null>(null);
  useEffect(() => { apiFetch("/api/admin/stats").then(setStats).catch(() => {}); }, []);

  if (!stats) return <div style={{ color: "#8a8680", fontSize: 14 }}>Lädt…</div>;

  const { security } = stats;
  const hasWarning = security.weakPassword || !security.totpEnabled;
  const actionColor = (a: string) => a.includes("FAIL") || a.includes("BLOCKED") ? "#f88" : a.includes("SUCCESS") || a.includes("CHANGED") || a.includes("ENABLED") ? "#6f6" : "#8a8680";

  return (
    <div>
      <h2 style={{ margin: "0 0 20px", fontSize: 20 }}>Übersicht</h2>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill,minmax(140px,1fr))", gap: 12, marginBottom: 24 }}>
        {[
          { label: "News", value: stats.news, tab: "news" as Tab, icon: "📰" },
          { label: "Termine", value: stats.events, tab: "events" as Tab, icon: "📅" },
          { label: "Fotos", value: stats.photos, tab: "photos" as Tab, icon: "🖼" },
          { label: "Lehrfilme", value: stats.videos, tab: "videos" as Tab, icon: "🎬" },
          { label: "Trainings/Woche", value: stats.trainingSessions, tab: "training" as Tab, icon: "🕐" },
          { label: "Trainer", value: stats.teamMembers, tab: "team" as Tab, icon: "👥" },
          { label: "Ferienperioden", value: stats.holidays, tab: "holidays" as Tab, icon: "🗓" },
          { label: "Neue Anfragen", value: stats.contactsUnread, tab: "contacts" as Tab, icon: "✉", highlight: stats.contactsUnread > 0 },
          { label: "Aktive Mitglieder", value: stats.mitgliederAktiv, tab: "team" as Tab, icon: "🥋" },
        ].map(({ label, value, tab, icon, highlight }) => (
          <button key={tab} onClick={() => onTabChange(tab)} style={{ ...S.statCard, cursor: "pointer", border: `1px solid ${highlight ? "#8B0000" : "#2a2a2a"}`, textAlign: "left" }}>
            <span style={{ fontSize: 20 }}>{icon}</span>
            <span style={{ fontSize: 28, fontWeight: 700, color: highlight ? "#8B0000" : "#e8e4df" }}>{value}</span>
            <span style={{ fontSize: 12, color: "#8a8680" }}>{label}</span>
          </button>
        ))}
      </div>

      <div style={S.secCard}>
        <div style={{ ...S.row, marginBottom: 12 }}>
          <h3 style={{ margin: 0, fontSize: 15, fontWeight: 700 }}>Nächste Termine</h3>
          <button style={S.btnSm} onClick={() => onTabChange("events")}>+ Termin eintragen</button>
        </div>
        {stats.nextEvents.length === 0 ? (
          <p style={{ color: "#8a8680", fontSize: 13 }}>Keine bevorstehenden Termine. <button style={{ ...S.btnGhost, fontSize: 12 }} onClick={() => onTabChange("events")}>Jetzt eintragen</button></p>
        ) : stats.nextEvents.map(e => (
          <div key={e.id} style={{ ...S.row, padding: "8px 0", borderBottom: "1px solid #1f1f1f" }}>
            <div>
              <div style={{ fontWeight: 600, fontSize: 14 }}>{e.titel}</div>
              <div style={{ fontSize: 12, color: "#8a8680" }}>{fmtDate(e.datum)} · {e.uhrzeit} · {e.ort}</div>
            </div>
            <span style={S.badgeInfo}>{e.typ}</span>
          </div>
        ))}
      </div>

      <div style={{ ...S.secCard, borderColor: hasWarning ? "#3a2a00" : "#2a2a2a" }}>
        <div style={{ ...S.row, marginBottom: 8 }}>
          <h3 style={{ margin: 0, fontSize: 15, fontWeight: 700 }}>Sicherheitsstatus</h3>
          <button style={S.btnGhost} onClick={() => onTabChange("security")}>Details →</button>
        </div>
        <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
          <span style={security.totpEnabled ? S.badgeOk : S.badgeDanger}>2FA: {security.totpEnabled ? "✓ Aktiv" : "✗ Inaktiv"}</span>
          <span style={security.weakPassword ? S.badgeDanger : S.badgeOk}>Passwort: {security.weakPassword ? "⚠ Standard" : "✓ Geändert"}</span>
        </div>
      </div>

      {stats.recentAudit.length > 0 && (
        <div style={S.secCard}>
          <h3 style={{ margin: "0 0 10px", fontSize: 15, fontWeight: 700 }}>Letzte Aktivitäten</h3>
          {stats.recentAudit.map((e, i) => (
            <div key={i} style={{ fontSize: 12, color: "#8a8680", padding: "4px 0", borderBottom: "1px solid #1a1a1a", display: "flex", gap: 10 }}>
              <span>{new Date(e.ts).toLocaleString("de-CH", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" })}</span>
              <span style={{ color: actionColor(e.action), fontWeight: 600 }}>{e.action}</span>
              <span>{e.detail}</span>
            </div>
          ))}
        </div>
      )}

      <div style={S.secCard}>
        <h3 style={{ margin: "0 0 12px", fontSize: 15, fontWeight: 700 }}>Schnellzugriff</h3>
        <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
          {[
            { label: "+ News schreiben", tab: "news" as Tab },
            { label: "+ Termin eintragen", tab: "events" as Tab },
            { label: "+ Foto hochladen", tab: "photos" as Tab },
            { label: "+ Lehrfilm hinzufügen", tab: "videos" as Tab },
            { label: "Anfragen ansehen", tab: "contacts" as Tab },
            { label: "Mitglied erfassen", tab: "team" as Tab },
            { label: "Prüfung eintragen", tab: "pruefungen" as Tab },
          ].map(({ label, tab }) => (
            <button key={tab} style={S.btnSm} onClick={() => onTabChange(tab)}>{label}</button>
          ))}
        </div>
      </div>
    </div>
  );
}

// ─── News ─────────────────────────────────────────────────────────────────────

type NewsForm = Omit<NewsItem, "id">;
const emptyNews = (): NewsForm => ({ titel: "", inhalt: "", publishedAt: new Date().toISOString().slice(0, 10), isFeatured: false, imageUrl: "" });

function NewsModal({ initial, onSave, onClose }: { initial: NewsForm; onSave: (d: NewsForm) => Promise<void>; onClose: () => void }) {
  const [form, setForm] = useState(initial); const [loading, setLoading] = useState(false);
  function set<K extends keyof NewsForm>(k: K, v: NewsForm[K]) { setForm(f => ({ ...f, [k]: v })); }
  async function submit(e: React.FormEvent) { e.preventDefault(); setLoading(true); try { await onSave(form); onClose(); } finally { setLoading(false); } }
  return (
    <Modal title={initial.titel ? "News bearbeiten" : "News hinzufügen"} onClose={onClose}>
      <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div><label style={S.label}>Titel *</label><input style={S.input} value={form.titel} onChange={e => set("titel", e.target.value)} required /></div>
        <div><label style={S.label}>Inhalt *</label><textarea style={S.textarea} value={form.inhalt} onChange={e => set("inhalt", e.target.value)} required /></div>
        <div><label style={S.label}>Datum</label><input type="date" style={S.input} value={form.publishedAt} onChange={e => set("publishedAt", e.target.value)} /></div>
        <div><label style={S.label}>Bild-URL (optional)</label><input style={S.input} value={form.imageUrl ?? ""} onChange={e => set("imageUrl", e.target.value)} /></div>
        <label style={{ display: "flex", gap: 8, cursor: "pointer", alignItems: "center" }}><input type="checkbox" checked={form.isFeatured} onChange={e => set("isFeatured", e.target.checked)} /><span style={{ fontSize: 13 }}>Als &quot;Aktuell&quot; hervorheben</span></label>
        <FormActions loading={loading} onClose={onClose} />
      </form>
    </Modal>
  );
}

function NewsManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [items, setItems] = useState<NewsItem[]>([]); const [modal, setModal] = useState<{ open: boolean; editing: NewsItem | null }>({ open: false, editing: null });
  const load = useCallback(async () => { try { setItems(await apiFetch("/api/admin/news")); } catch { toast("Fehler beim Laden", "err"); } }, [toast]);
  useEffect(() => { load(); }, [load]);
  async function save(data: NewsForm) {
    if (modal.editing) { await apiFetch(`/api/admin/news/${modal.editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Aktualisiert"); }
    else { await apiFetch("/api/admin/news", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Hinzugefügt"); }
    await load();
  }
  async function del(id: string) { if (!confirm("Wirklich löschen?")) return; await apiFetch(`/api/admin/news/${id}`, { method: "DELETE" }); toast("Gelöscht"); await load(); }
  async function toggleFeatured(item: NewsItem) { await apiFetch(`/api/admin/news/${item.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ isFeatured: !item.isFeatured }) }); await load(); }
  return (
    <div>
      <div style={{ ...S.row, marginBottom: 20 }}><h2 style={{ margin: 0, fontSize: 20 }}>News</h2><button style={S.btn} onClick={() => setModal({ open: true, editing: null })}>+ Neue News</button></div>
      {items.length === 0 && <p style={{ color: "#8a8680", fontSize: 14 }}>Noch keine News vorhanden.</p>}
      {items.map(item => (
        <div key={item.id} style={S.card}>
          <div style={S.row}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: "flex", gap: 8, marginBottom: 4 }}>
                {item.isFeatured && <span style={{ ...S.badge, marginLeft: 0, fontSize: 10 }}>AKTUELL</span>}
                <span style={{ fontSize: 11, color: "#8a8680" }}>{fmtDate(item.publishedAt)}</span>
              </div>
              <div style={{ fontWeight: 600, fontSize: 15, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", marginBottom: 3 }}>{item.titel}</div>
              <div style={{ fontSize: 13, color: "#8a8680", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.inhalt.slice(0, 100)}…</div>
            </div>
            <div style={S.actions}>
              <button style={{ ...S.btnGhost, color: item.isFeatured ? "#C8960C" : undefined }} onClick={() => toggleFeatured(item)} title="Als Aktuell markieren">★</button>
              <button style={S.btnSm} onClick={() => setModal({ open: true, editing: item })}>Bearbeiten</button>
              <button style={S.btnDanger} onClick={() => del(item.id)}>Löschen</button>
            </div>
          </div>
        </div>
      ))}
      {modal.open && <NewsModal initial={modal.editing ? { titel: modal.editing.titel, inhalt: modal.editing.inhalt, publishedAt: modal.editing.publishedAt, isFeatured: modal.editing.isFeatured, imageUrl: modal.editing.imageUrl ?? "" } : emptyNews()} onSave={save} onClose={() => setModal({ open: false, editing: null })} />}
    </div>
  );
}

// ─── Events ───────────────────────────────────────────────────────────────────

const EVENT_TYPEN = ["Prüfung", "Lehrgang", "Wettkampf", "Anlass", "Trainingslager"];
type EventForm = Omit<EventItem, "id">;
const emptyEvent = (): EventForm => ({ titel: "", datum: new Date().toISOString().slice(0, 10), datumLabel: "", uhrzeit: "", ort: "", typ: "Anlass", beschreibung: "", isPublic: true });

function EventModal({ initial, onSave, onClose }: { initial: EventForm; onSave: (d: EventForm) => Promise<void>; onClose: () => void }) {
  const [form, setForm] = useState(initial); const [loading, setLoading] = useState(false);
  function set<K extends keyof EventForm>(k: K, v: EventForm[K]) { setForm(f => ({ ...f, [k]: v })); }
  async function submit(e: React.FormEvent) { e.preventDefault(); setLoading(true); try { await onSave(form); onClose(); } finally { setLoading(false); } }
  return (
    <Modal title={initial.titel ? "Termin bearbeiten" : "Termin hinzufügen"} onClose={onClose}>
      <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div><label style={S.label}>Titel *</label><input style={S.input} value={form.titel} onChange={e => set("titel", e.target.value)} required /></div>
        <div style={{ display: "flex", gap: 10 }}>
          <div style={{ flex: 1 }}><label style={S.label}>Datum *</label><input type="date" style={S.input} value={form.datum} onChange={e => set("datum", e.target.value)} required /></div>
          <div style={{ flex: 1 }}><label style={S.label}>Datumsanzeige</label><input style={S.input} value={form.datumLabel} onChange={e => set("datumLabel", e.target.value)} placeholder="z. B. 14. Mai 2026" /></div>
        </div>
        <div style={{ display: "flex", gap: 10 }}>
          <div style={{ flex: 1 }}><label style={S.label}>Uhrzeit</label><input style={S.input} value={form.uhrzeit} onChange={e => set("uhrzeit", e.target.value)} placeholder="19:00 Uhr" /></div>
          <div style={{ flex: 1 }}><label style={S.label}>Ort *</label><input style={S.input} value={form.ort} onChange={e => set("ort", e.target.value)} required /></div>
        </div>
        <div><label style={S.label}>Typ</label><select style={S.select} value={form.typ} onChange={e => set("typ", e.target.value)}>{EVENT_TYPEN.map(t => <option key={t} value={t}>{t}</option>)}</select></div>
        <div><label style={S.label}>Beschreibung</label><textarea style={S.textarea} value={form.beschreibung} onChange={e => set("beschreibung", e.target.value)} /></div>
        <label style={{ display: "flex", gap: 8, cursor: "pointer", alignItems: "center" }}><input type="checkbox" checked={form.isPublic} onChange={e => set("isPublic", e.target.checked)} /><span style={{ fontSize: 13 }}>Öffentlich sichtbar</span></label>
        <FormActions loading={loading} onClose={onClose} />
      </form>
    </Modal>
  );
}

function EventCard({ item, onEdit, onDel, muted }: { item: EventItem; onEdit: () => void; onDel: () => void; muted?: boolean }) {
  return (
    <div style={{ ...S.card, opacity: muted ? 0.6 : 1 }}>
      <div style={S.row}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: "flex", gap: 8, marginBottom: 4, flexWrap: "wrap" }}>
            <span style={S.badgeInfo}>{item.typ}</span>
            <span style={{ fontSize: 12, color: "#8a8680" }}>{fmtDate(item.datum)} {item.uhrzeit && `· ${item.uhrzeit}`} {item.ort && `· ${item.ort}`}</span>
          </div>
          <div style={{ fontWeight: 600, fontSize: 15, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.titel}</div>
          {item.beschreibung && <div style={{ fontSize: 13, color: "#8a8680", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", marginTop: 2 }}>{item.beschreibung}</div>}
        </div>
        <div style={S.actions}>
          <button style={S.btnSm} onClick={onEdit}>Bearbeiten</button>
          <button style={S.btnDanger} onClick={onDel}>Löschen</button>
        </div>
      </div>
    </div>
  );
}

function EventsManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [items, setItems] = useState<EventItem[]>([]); const [modal, setModal] = useState<{ open: boolean; editing: EventItem | null }>({ open: false, editing: null });
  const load = useCallback(async () => { try { setItems(await apiFetch("/api/admin/events")); } catch { toast("Fehler", "err"); } }, [toast]);
  useEffect(() => { load(); }, [load]);
  async function save(data: EventForm) {
    if (modal.editing) { await apiFetch(`/api/admin/events/${modal.editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Aktualisiert"); }
    else { await apiFetch("/api/admin/events", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Termin hinzugefügt"); }
    await load();
  }
  async function del(id: string) { if (!confirm("Wirklich löschen?")) return; await apiFetch(`/api/admin/events/${id}`, { method: "DELETE" }); toast("Gelöscht"); await load(); }
  const today = new Date().toISOString().slice(0, 10);
  const upcoming = items.filter(e => e.datum >= today);
  const past = items.filter(e => e.datum < today);
  return (
    <div>
      <div style={{ ...S.row, marginBottom: 20 }}><h2 style={{ margin: 0, fontSize: 20 }}>Termine &amp; Anlässe</h2><button style={S.btn} onClick={() => setModal({ open: true, editing: null })}>+ Termin eintragen</button></div>
      {items.length === 0 && <p style={{ color: "#8a8680", fontSize: 14 }}>Noch keine Termine. Füge Prüfungen, Lehrgänge und Anlässe hinzu — sie erscheinen automatisch auf <code>/termine</code>.</p>}
      {upcoming.length > 0 && <p style={{ fontSize: 12, color: "#8a8680", marginBottom: 8, fontWeight: 600 }}>BEVORSTEHEND</p>}
      {upcoming.map(item => <EventCard key={item.id} item={item} onEdit={() => setModal({ open: true, editing: item })} onDel={() => del(item.id)} />)}
      {past.length > 0 && <p style={{ fontSize: 12, color: "#8a8680", marginTop: 16, marginBottom: 8, fontWeight: 600 }}>VERGANGEN</p>}
      {past.map(item => <EventCard key={item.id} item={item} onEdit={() => setModal({ open: true, editing: item })} onDel={() => del(item.id)} muted />)}
      {modal.open && <EventModal initial={modal.editing ? { titel: modal.editing.titel, datum: modal.editing.datum, datumLabel: modal.editing.datumLabel, uhrzeit: modal.editing.uhrzeit, ort: modal.editing.ort, typ: modal.editing.typ, beschreibung: modal.editing.beschreibung, isPublic: modal.editing.isPublic } : emptyEvent()} onSave={save} onClose={() => setModal({ open: false, editing: null })} />}
    </div>
  );
}

// ─── Training ─────────────────────────────────────────────────────────────────

type SessionForm = Omit<TrainingSession, "id" | "order">;
const emptySession = (): SessionForm => ({ tag: "Montag", startTime: "19:00", endTime: "20:30", gruppe: "Jugendliche & Erwachsene", level: "Jugend & Erwachsene", halle: "Trainingshalle Arbon", aktiv: true });
const WOCHENTAGE = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"];

function SessionModal({ initial, onSave, onClose }: { initial: SessionForm; onSave: (d: SessionForm) => Promise<void>; onClose: () => void }) {
  const [form, setForm] = useState(initial); const [loading, setLoading] = useState(false);
  function set<K extends keyof SessionForm>(k: K, v: SessionForm[K]) { setForm(f => ({ ...f, [k]: v })); }
  async function submit(e: React.FormEvent) { e.preventDefault(); setLoading(true); try { await onSave(form); onClose(); } finally { setLoading(false); } }
  return (
    <Modal title="Trainingszeit" onClose={onClose}>
      <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div><label style={S.label}>Wochentag</label><select style={S.select} value={form.tag} onChange={e => set("tag", e.target.value)}>{WOCHENTAGE.map(d => <option key={d} value={d}>{d}</option>)}</select></div>
        <div style={{ display: "flex", gap: 10 }}>
          <div style={{ flex: 1 }}><label style={S.label}>Von</label><input style={S.input} value={form.startTime} onChange={e => set("startTime", e.target.value)} placeholder="19:00" /></div>
          <div style={{ flex: 1 }}><label style={S.label}>Bis</label><input style={S.input} value={form.endTime} onChange={e => set("endTime", e.target.value)} placeholder="20:30" /></div>
        </div>
        <div><label style={S.label}>Gruppe</label><input style={S.input} value={form.gruppe} onChange={e => set("gruppe", e.target.value)} /></div>
        <div><label style={S.label}>Level</label><input style={S.input} value={form.level} onChange={e => set("level", e.target.value)} /></div>
        <div><label style={S.label}>Halle</label><input style={S.input} value={form.halle} onChange={e => set("halle", e.target.value)} /></div>
        <label style={{ display: "flex", gap: 8, cursor: "pointer", alignItems: "center" }}><input type="checkbox" checked={form.aktiv} onChange={e => set("aktiv", e.target.checked)} /><span style={{ fontSize: 13 }}>Aktiv (auf Website anzeigen)</span></label>
        <FormActions loading={loading} onClose={onClose} />
      </form>
    </Modal>
  );
}

function TrainingManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [items, setItems] = useState<TrainingSession[]>([]); const [modal, setModal] = useState<{ open: boolean; editing: TrainingSession | null }>({ open: false, editing: null });
  const load = useCallback(async () => { try { setItems(await apiFetch("/api/admin/training-sessions")); } catch { toast("Fehler", "err"); } }, [toast]);
  useEffect(() => { load(); }, [load]);
  async function save(data: SessionForm) {
    if (modal.editing) { await apiFetch(`/api/admin/training-sessions/${modal.editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Aktualisiert"); }
    else { await apiFetch("/api/admin/training-sessions", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Hinzugefügt"); }
    await load();
  }
  async function del(id: string) { if (!confirm("Wirklich löschen?")) return; await apiFetch(`/api/admin/training-sessions/${id}`, { method: "DELETE" }); toast("Gelöscht"); await load(); }
  async function toggle(item: TrainingSession) { await apiFetch(`/api/admin/training-sessions/${item.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ aktiv: !item.aktiv }) }); await load(); }
  return (
    <div>
      <div style={{ ...S.row, marginBottom: 8 }}><h2 style={{ margin: 0, fontSize: 20 }}>Trainingszeiten</h2><button style={S.btn} onClick={() => setModal({ open: true, editing: null })}>+ Zeit hinzufügen</button></div>
      <p style={{ fontSize: 12, color: "#8a8680", marginBottom: 20 }}>Änderungen wirken sich sofort auf Startseite und <code>/trainingszeiten</code> aus.</p>
      {items.map(item => (
        <div key={item.id} style={{ ...S.card, opacity: item.aktiv ? 1 : 0.5 }}>
          <div style={S.row}>
            <div>
              <div style={{ display: "flex", gap: 8, marginBottom: 4 }}>
                <span style={item.aktiv ? S.badgeOk : S.badgeDanger}>{item.aktiv ? "Aktiv" : "Inaktiv"}</span>
              </div>
              <div style={{ fontWeight: 700, fontSize: 16 }}>{item.tag}</div>
              <div style={{ fontSize: 14, color: "#8a8680" }}>{item.startTime}–{item.endTime} · {item.gruppe} · {item.halle}</div>
            </div>
            <div style={S.actions}>
              <button style={S.btnGhost} onClick={() => toggle(item)}>{item.aktiv ? "Pausieren" : "Aktivieren"}</button>
              <button style={S.btnSm} onClick={() => setModal({ open: true, editing: item })}>Bearbeiten</button>
              <button style={S.btnDanger} onClick={() => del(item.id)}>×</button>
            </div>
          </div>
        </div>
      ))}
      {modal.open && <SessionModal initial={modal.editing ? { tag: modal.editing.tag, startTime: modal.editing.startTime, endTime: modal.editing.endTime, gruppe: modal.editing.gruppe, level: modal.editing.level, halle: modal.editing.halle, aktiv: modal.editing.aktiv } : emptySession()} onSave={save} onClose={() => setModal({ open: false, editing: null })} />}
    </div>
  );
}

// ─── Pricing ─────────────────────────────────────────────────────────────────

type PricingForm = Omit<PricingTier, "id" | "order">;
const emptyPricing = (): PricingForm => ({ bezeichnung: "", beschreibung: "", zeilen: [{ periode: "", betragChf: 0 }], features: [""], empfohlen: false, cta: "Jetzt anmelden" });

function PricingModal({ initial, onSave, onClose }: { initial: PricingForm; onSave: (d: PricingForm) => Promise<void>; onClose: () => void }) {
  const [form, setForm] = useState<PricingForm>(initial); const [loading, setLoading] = useState(false);
  async function submit(e: React.FormEvent) { e.preventDefault(); setLoading(true); try { await onSave({ ...form, features: form.features.filter(f => f.trim()), zeilen: form.zeilen.filter(z => z.periode.trim()) }); onClose(); } finally { setLoading(false); } }
  return (
    <Modal title="Preiskategorie" onClose={onClose}>
      <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div><label style={S.label}>Bezeichnung *</label><input style={S.input} value={form.bezeichnung} onChange={e => setForm(f => ({ ...f, bezeichnung: e.target.value }))} required /></div>
        <div><label style={S.label}>Beschreibung</label><textarea style={{ ...S.textarea, minHeight: 60 }} value={form.beschreibung} onChange={e => setForm(f => ({ ...f, beschreibung: e.target.value }))} /></div>
        <div>
          <label style={S.label}>Preiszeilen</label>
          {form.zeilen.map((z, i) => (
            <div key={i} style={{ display: "flex", gap: 6, marginBottom: 6 }}>
              <input style={{ ...S.input, flex: 2 }} value={z.periode} onChange={e => { const z2 = [...form.zeilen]; z2[i] = { ...z2[i], periode: e.target.value }; setForm(f => ({ ...f, zeilen: z2 })); }} placeholder="Bezeichnung (z. B. Jahresbeitrag)" />
              <input type="number" style={{ ...S.input, flex: 1 }} value={z.betragChf} onChange={e => { const z2 = [...form.zeilen]; z2[i] = { ...z2[i], betragChf: Number(e.target.value) }; setForm(f => ({ ...f, zeilen: z2 })); }} placeholder="CHF" />
              <button type="button" style={S.btnDanger} onClick={() => setForm(f => ({ ...f, zeilen: f.zeilen.filter((_, j) => j !== i) }))}>×</button>
            </div>
          ))}
          <button type="button" style={S.btnGhost} onClick={() => setForm(f => ({ ...f, zeilen: [...f.zeilen, { periode: "", betragChf: 0 }] }))}>+ Zeile</button>
        </div>
        <div>
          <label style={S.label}>Features</label>
          {form.features.map((feat, i) => (
            <div key={i} style={{ display: "flex", gap: 6, marginBottom: 6 }}>
              <input style={S.input} value={feat} onChange={e => { const f2 = [...form.features]; f2[i] = e.target.value; setForm(f => ({ ...f, features: f2 })); }} />
              <button type="button" style={S.btnDanger} onClick={() => setForm(f => ({ ...f, features: f.features.filter((_, j) => j !== i) }))}>×</button>
            </div>
          ))}
          <button type="button" style={S.btnGhost} onClick={() => setForm(f => ({ ...f, features: [...f.features, ""] }))}>+ Feature</button>
        </div>
        <div style={{ display: "flex", gap: 10 }}>
          <div style={{ flex: 1 }}><label style={S.label}>CTA-Button Text</label><input style={S.input} value={form.cta} onChange={e => setForm(f => ({ ...f, cta: e.target.value }))} /></div>
          <label style={{ display: "flex", gap: 8, cursor: "pointer", alignItems: "center", flexShrink: 0 }}><input type="checkbox" checked={form.empfohlen ?? false} onChange={e => setForm(f => ({ ...f, empfohlen: e.target.checked }))} /><span style={{ fontSize: 13 }}>Empfohlen</span></label>
        </div>
        <FormActions loading={loading} onClose={onClose} />
      </form>
    </Modal>
  );
}

function PricingManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [items, setItems] = useState<PricingTier[]>([]); const [modal, setModal] = useState<{ open: boolean; editing: PricingTier | null }>({ open: false, editing: null });
  const load = useCallback(async () => { try { setItems(await apiFetch("/api/admin/pricing")); } catch { toast("Fehler", "err"); } }, [toast]);
  useEffect(() => { load(); }, [load]);
  async function save(data: PricingForm) {
    if (modal.editing) { await apiFetch(`/api/admin/pricing/${modal.editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Aktualisiert"); }
    else { await apiFetch("/api/admin/pricing", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Hinzugefügt"); }
    await load();
  }
  async function del(id: string) { if (!confirm("Wirklich löschen?")) return; await apiFetch(`/api/admin/pricing/${id}`, { method: "DELETE" }); toast("Gelöscht"); await load(); }
  return (
    <div>
      <div style={{ ...S.row, marginBottom: 8 }}><h2 style={{ margin: 0, fontSize: 20 }}>Mitgliedschaft &amp; Preise</h2><button style={S.btn} onClick={() => setModal({ open: true, editing: null })}>+ Kategorie</button></div>
      <p style={{ fontSize: 12, color: "#8a8680", marginBottom: 20 }}>Änderungen erscheinen sofort auf <code>/preise</code>.</p>
      {items.map(item => (
        <div key={item.id} style={S.card}>
          <div style={S.row}>
            <div style={{ flex: 1 }}>
              <div style={{ display: "flex", gap: 8, marginBottom: 4 }}>{item.empfohlen && <span style={{ ...S.badge, marginLeft: 0, fontSize: 10 }}>EMPFOHLEN</span>}</div>
              <div style={{ fontWeight: 700, fontSize: 16 }}>{item.bezeichnung}</div>
              <div style={{ fontSize: 13, color: "#8a8680", marginTop: 2 }}>{item.zeilen.map(z => `CHF ${z.betragChf} / ${z.periode}`).join(" · ")}</div>
              <div style={{ fontSize: 12, color: "#555", marginTop: 4 }}>{item.features.slice(0, 2).join(" · ")}{item.features.length > 2 ? ` · +${item.features.length - 2} weitere` : ""}</div>
            </div>
            <div style={S.actions}>
              <button style={S.btnSm} onClick={() => setModal({ open: true, editing: item })}>Bearbeiten</button>
              <button style={S.btnDanger} onClick={() => del(item.id)}>Löschen</button>
            </div>
          </div>
        </div>
      ))}
      {modal.open && <PricingModal initial={modal.editing ? { bezeichnung: modal.editing.bezeichnung, beschreibung: modal.editing.beschreibung, zeilen: modal.editing.zeilen, features: modal.editing.features, empfohlen: modal.editing.empfohlen, cta: modal.editing.cta } : emptyPricing()} onSave={save} onClose={() => setModal({ open: false, editing: null })} />}
    </div>
  );
}

// ─── Team ─────────────────────────────────────────────────────────────────────

function TrainerModal({ initial, onSave, onClose }: { initial: TeamMember | null; onSave: (d: Omit<TeamMember, "id" | "order">) => Promise<void>; onClose: () => void }) {
  const [form, setForm] = useState<Omit<TeamMember, "id" | "order">>({
    name: initial?.name ?? "", rolle: initial?.rolle ?? "Trainer", grad: initial?.grad ?? "", bio: initial?.bio ?? "", imageUrl: initial?.imageUrl ?? "", isCheftrainer: initial?.isCheftrainer ?? false,
  });
  const [loading, setLoading] = useState(false);
  const fileRef = useRef<HTMLInputElement>(null);
  const [uploading, setUploading] = useState(false);

  async function uploadFile(file: File) {
    setUploading(true);
    try {
      const fd = new FormData(); fd.append("file", file);
      const res = await fetch("/api/admin/upload", { method: "POST", credentials: "include", body: fd });
      const data = await res.json();
      setForm(f => ({ ...f, imageUrl: data.src }));
    } finally { setUploading(false); }
  }
  async function submit(e: React.FormEvent) { e.preventDefault(); setLoading(true); try { await onSave(form); onClose(); } finally { setLoading(false); } }

  return (
    <Modal title={initial ? "Trainer bearbeiten" : "Trainer hinzufügen"} onClose={onClose}>
      <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div><label style={S.label}>Name *</label><input style={S.input} value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))} required /></div>
        <div><label style={S.label}>Rolle</label><input style={S.input} value={form.rolle} onChange={e => setForm(f => ({ ...f, rolle: e.target.value }))} /></div>
        <div><label style={S.label}>Grad (z. B. 5. Dan)</label><input style={S.input} value={form.grad ?? ""} onChange={e => setForm(f => ({ ...f, grad: e.target.value }))} /></div>
        <div><label style={S.label}>Biografie</label><textarea style={S.textarea} value={form.bio ?? ""} onChange={e => setForm(f => ({ ...f, bio: e.target.value }))} /></div>
        <div>
          <label style={S.label}>Foto</label>
          <input ref={fileRef} type="file" accept="image/*" style={{ display: "none" }} onChange={e => { const f = e.target.files?.[0]; if (f) uploadFile(f); }} />
          <div style={{ display: "flex", gap: 8 }}>
            <input style={{ ...S.input, flex: 1 }} value={form.imageUrl ?? ""} onChange={e => setForm(f => ({ ...f, imageUrl: e.target.value }))} placeholder="/images/..." />
            <button type="button" style={S.btnGhost} onClick={() => fileRef.current?.click()} disabled={uploading}>{uploading ? "…" : "Hochladen"}</button>
          </div>
          {form.imageUrl && <img src={form.imageUrl} alt="" style={{ marginTop: 8, maxHeight: 100, objectFit: "cover", borderRadius: 4 }} />}
        </div>
        <label style={{ display: "flex", gap: 8, cursor: "pointer", alignItems: "center" }}><input type="checkbox" checked={form.isCheftrainer ?? false} onChange={e => setForm(f => ({ ...f, isCheftrainer: e.target.checked }))} /><span style={{ fontSize: 13 }}>Als Cheftrainer kennzeichnen</span></label>
        <FormActions loading={loading} onClose={onClose} />
      </form>
    </Modal>
  );
}

function TeamManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [team, setTeam] = useState<TeamData>({ trainer: [], vorstand: [], mitglieder: [] });
  const [editTrainer, setEditTrainer] = useState<TeamMember | null>(null);
  const [addTrainer, setAddTrainer] = useState(false);
  const [saving, setSaving] = useState(false);

  const load = useCallback(async () => {
    try { const data = await apiFetch("/api/admin/team"); setTeam(data); } catch { toast("Fehler", "err"); }
  }, [toast]);
  useEffect(() => { load(); }, [load]);

  async function saveTeam(newTeam: TeamData) {
    setSaving(true);
    try { await apiFetch("/api/admin/team", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(newTeam) }); toast("Gespeichert"); await load(); }
    catch { toast("Fehler beim Speichern", "err"); } finally { setSaving(false); }
  }

  async function saveTrainer(data: Omit<TeamMember, "id" | "order">, editing: TeamMember | null) {
    let trainers: TeamMember[];
    if (editing) { trainers = team.trainer.map(t => t.id === editing.id ? { ...t, ...data } : t); }
    else { trainers = [...team.trainer, { ...data, id: newId(), order: team.trainer.length }]; }
    await saveTeam({ ...team, trainer: trainers });
    setEditTrainer(null); setAddTrainer(false);
  }

  async function delTrainer(id: string) {
    if (!confirm("Trainer löschen?")) return;
    await saveTeam({ ...team, trainer: team.trainer.filter(t => t.id !== id) });
  }

  function addVorstandRow() { setTeam(t => ({ ...t, vorstand: [...t.vorstand, { id: newId(), funktion: "", person: "", order: t.vorstand.length }] })); }
  function updateVorstand(id: string, key: "funktion" | "person", val: string) { setTeam(t => ({ ...t, vorstand: t.vorstand.map(v => v.id === id ? { ...v, [key]: val } : v) })); }
  function delVorstand(id: string) { setTeam(t => ({ ...t, vorstand: t.vorstand.filter(v => v.id !== id) })); }
  function moveVorstand(id: string, dir: -1 | 1) {
    setTeam(t => {
      const sorted = [...t.vorstand].sort((a, b) => a.order - b.order);
      const idx = sorted.findIndex(v => v.id === id);
      const next = idx + dir;
      if (next < 0 || next >= sorted.length) return t;
      [sorted[idx], sorted[next]] = [sorted[next], sorted[idx]];
      return { ...t, vorstand: sorted.map((v, i) => ({ ...v, order: i })) };
    });
  }

  async function saveVorstand() { await saveTeam(team); }

  return (
    <div>
      <h2 style={{ margin: "0 0 20px", fontSize: 20 }}>Trainer &amp; Vorstand</h2>

      <div style={S.secCard}>
        <div style={{ ...S.row, marginBottom: 12 }}>
          <h3 style={{ margin: 0, fontSize: 15, fontWeight: 700 }}>Trainer</h3>
          <button style={S.btnSm} onClick={() => setAddTrainer(true)}>+ Trainer hinzufügen</button>
        </div>
        {team.trainer.sort((a, b) => a.order - b.order).map(t => (
          <div key={t.id} style={{ ...S.row, padding: "10px 0", borderBottom: "1px solid #1f1f1f" }}>
            <div>
              <div style={{ display: "flex", gap: 6, marginBottom: 2 }}>
                {t.isCheftrainer && <span style={{ ...S.badge, marginLeft: 0, fontSize: 10 }}>CHEFTRAINER</span>}
              </div>
              <div style={{ fontWeight: 600 }}>{t.name}</div>
              <div style={{ fontSize: 12, color: "#8a8680" }}>{t.rolle}{t.grad ? ` · ${t.grad}` : ""}</div>
              {t.imageUrl && <div style={{ fontSize: 11, color: "#555", marginTop: 2 }}>📷 {t.imageUrl}</div>}
            </div>
            <div style={S.actions}>
              <button style={S.btnSm} onClick={() => setEditTrainer(t)}>Bearbeiten</button>
              <button style={S.btnDanger} onClick={() => delTrainer(t.id)}>Löschen</button>
            </div>
          </div>
        ))}
      </div>

      <div style={S.secCard}>
        <h3 style={{ margin: "0 0 12px", fontSize: 15, fontWeight: 700 }}>Vorstand</h3>
        {team.vorstand.sort((a, b) => a.order - b.order).map((v, i, arr) => (
          <div key={v.id} style={{ display: "flex", gap: 8, marginBottom: 8, alignItems: "center" }}>
            <div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
              <button style={{ ...S.btnGhost, padding: "2px 6px", fontSize: 11, lineHeight: 1 }} disabled={i === 0} onClick={() => moveVorstand(v.id, -1)}>▲</button>
              <button style={{ ...S.btnGhost, padding: "2px 6px", fontSize: 11, lineHeight: 1 }} disabled={i === arr.length - 1} onClick={() => moveVorstand(v.id, 1)}>▼</button>
            </div>
            <input style={{ ...S.input, flex: 1 }} value={v.funktion} onChange={e => updateVorstand(v.id, "funktion", e.target.value)} placeholder="Funktion (z. B. Kassier)" />
            <input style={{ ...S.input, flex: 1 }} value={v.person} onChange={e => updateVorstand(v.id, "person", e.target.value)} placeholder="Name" />
            <button style={S.btnDanger} onClick={() => delVorstand(v.id)}>×</button>
          </div>
        ))}
        <div style={{ display: "flex", gap: 8, marginTop: 8 }}>
          <button style={S.btnGhost} onClick={addVorstandRow}>+ Zeile</button>
          <button style={S.btnSm} disabled={saving} onClick={saveVorstand}>{saving ? "…" : "Speichern"}</button>
        </div>
      </div>

      {(editTrainer || addTrainer) && <TrainerModal initial={editTrainer} onSave={(data) => saveTrainer(data, editTrainer)} onClose={() => { setEditTrainer(null); setAddTrainer(false); }} />}
    </div>
  );
}

// ─── Photos ───────────────────────────────────────────────────────────────────

function PhotoModal({ initial, onSave, onClose }: { initial: Photo | null; onSave: (d: Omit<Photo, "id" | "order">, e: Photo | null) => Promise<void>; onClose: () => void }) {
  const [form, setForm] = useState({ src: initial?.src ?? "", alt: initial?.alt ?? "", caption: initial?.caption ?? "", width: initial?.width ?? 640, height: initial?.height ?? 480 });
  const [loading, setLoading] = useState(false);
  async function submit(e: React.FormEvent) { e.preventDefault(); setLoading(true); try { await onSave(form, initial); } finally { setLoading(false); } }
  return (
    <Modal title={initial ? "Foto bearbeiten" : "Foto per URL"} onClose={onClose}>
      <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div><label style={S.label}>URL *</label><input style={S.input} value={form.src} onChange={e => setForm(f => ({ ...f, src: e.target.value }))} required /></div>
        {form.src && <img src={form.src} alt="" style={{ maxHeight: 120, objectFit: "contain", borderRadius: 4 }} />}
        <div><label style={S.label}>Alt-Text *</label><input style={S.input} value={form.alt} onChange={e => setForm(f => ({ ...f, alt: e.target.value }))} required /></div>
        <div><label style={S.label}>Bildunterschrift</label><input style={S.input} value={form.caption} onChange={e => setForm(f => ({ ...f, caption: e.target.value }))} /></div>
        <div style={{ display: "flex", gap: 10 }}>
          <div style={{ flex: 1 }}><label style={S.label}>Breite px</label><input type="number" style={S.input} value={form.width} onChange={e => setForm(f => ({ ...f, width: Number(e.target.value) }))} /></div>
          <div style={{ flex: 1 }}><label style={S.label}>Höhe px</label><input type="number" style={S.input} value={form.height} onChange={e => setForm(f => ({ ...f, height: Number(e.target.value) }))} /></div>
        </div>
        <FormActions loading={loading} onClose={onClose} />
      </form>
    </Modal>
  );
}

function PhotoManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [items, setItems] = useState<Photo[]>([]); const [modal, setModal] = useState<{ open: boolean; editing: Photo | null }>({ open: false, editing: null });
  const fileRef = useRef<HTMLInputElement>(null); const [uploading, setUploading] = useState(false);
  const load = useCallback(async () => { try { setItems(await apiFetch("/api/admin/photos")); } catch { toast("Fehler", "err"); } }, [toast]);
  useEffect(() => { load(); }, [load]);

  async function uploadFile(file: File) {
    setUploading(true);
    try {
      const fd = new FormData(); fd.append("file", file);
      const res = await fetch("/api/admin/upload", { method: "POST", credentials: "include", body: fd });
      const data = await res.json();
      await apiFetch("/api/admin/photos", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ src: data.src, alt: file.name.replace(/\.[^.]+$/, ""), width: 640, height: 480 }) });
      toast("Foto hochgeladen"); await load();
    } catch { toast("Upload fehlgeschlagen", "err"); } finally { setUploading(false); }
  }

  async function save(data: Omit<Photo, "id" | "order">, editing: Photo | null) {
    if (editing) { await apiFetch(`/api/admin/photos/${editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Aktualisiert"); }
    else { await apiFetch("/api/admin/photos", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Hinzugefügt"); }
    await load(); setModal({ open: false, editing: null });
  }

  async function del(id: string) { if (!confirm("Foto löschen?")) return; await apiFetch(`/api/admin/photos/${id}`, { method: "DELETE" }); toast("Gelöscht"); await load(); }
  async function move(id: string, dir: -1 | 1) {
    const sorted = [...items].sort((a, b) => a.order - b.order); const idx = sorted.findIndex(p => p.id === id); const swap = idx + dir;
    if (swap < 0 || swap >= sorted.length) return;
    await apiFetch("/api/admin/photos", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify([{ id: sorted[idx].id, order: sorted[swap].order }, { id: sorted[swap].id, order: sorted[idx].order }]) });
    await load();
  }

  const sorted = [...items].sort((a, b) => a.order - b.order);
  return (
    <div>
      <div style={{ ...S.row, marginBottom: 8 }}>
        <h2 style={{ margin: 0, fontSize: 20 }}>Fotos</h2>
        <div style={{ display: "flex", gap: 8 }}>
          <input ref={fileRef} type="file" accept="image/*" style={{ display: "none" }} onChange={e => { const f = e.target.files?.[0]; if (f) uploadFile(f); }} />
          <button style={S.btnGhost} onClick={() => fileRef.current?.click()} disabled={uploading}>{uploading ? "Lädt hoch…" : "Hochladen"}</button>
          <button style={S.btn} onClick={() => setModal({ open: true, editing: null })}>+ URL hinzufügen</button>
        </div>
      </div>
      <p style={{ fontSize: 12, color: "#8a8680", marginBottom: 20 }}>{items.length} Fotos · Reihenfolge per ↑↓</p>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill,minmax(180px,1fr))", gap: 12 }}>
        {sorted.map((photo, i) => (
          <div key={photo.id} style={{ background: "#1a1a1a", border: "1px solid #2a2a2a", borderRadius: 8, overflow: "hidden" }}>
            <div style={{ position: "relative", paddingTop: "66%", background: "#111" }}>
              <img src={photo.src} alt={photo.alt} style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }} />
              <span style={{ position: "absolute", top: 4, left: 4, background: "rgba(0,0,0,0.7)", color: "#fff", fontSize: 10, padding: "1px 5px", borderRadius: 3, fontWeight: 700 }}>#{i + 1}</span>
            </div>
            <div style={{ padding: "8px 10px" }}>
              <div style={{ fontSize: 11, color: "#8a8680", marginBottom: 6, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{photo.caption || photo.alt}</div>
              <div style={{ display: "flex", gap: 4, flexWrap: "wrap" }}>
                <button style={S.btnGhost} disabled={i === 0} onClick={() => move(photo.id, -1)}>↑</button>
                <button style={S.btnGhost} disabled={i === sorted.length - 1} onClick={() => move(photo.id, 1)}>↓</button>
                <button style={S.btnSm} onClick={() => setModal({ open: true, editing: photo })}>✎</button>
                <button style={S.btnDanger} onClick={() => del(photo.id)}>×</button>
              </div>
            </div>
          </div>
        ))}
      </div>
      {modal.open && <PhotoModal initial={modal.editing} onSave={save} onClose={() => setModal({ open: false, editing: null })} />}
    </div>
  );
}

// ─── Videos ───────────────────────────────────────────────────────────────────

type VideoForm = Omit<VideoItem, "id" | "order">;
const emptyVideo = (): VideoForm => ({ type: "embed", title: "", description: "" });

function VideoModal({ initial, onSave, onClose }: { initial: VideoForm; onSave: (d: VideoForm) => Promise<void>; onClose: () => void }) {
  const [form, setForm] = useState(initial); const [loading, setLoading] = useState(false);
  function set<K extends keyof VideoForm>(k: K, v: VideoForm[K]) { setForm(f => ({ ...f, [k]: v })); }
  async function submit(e: React.FormEvent) { e.preventDefault(); setLoading(true); try { await onSave(form); onClose(); } finally { setLoading(false); } }
  return (
    <Modal title={initial.title ? "Lehrfilm bearbeiten" : "Lehrfilm hinzufügen"} onClose={onClose}>
      <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div><label style={S.label}>Typ</label><select style={S.select} value={form.type} onChange={e => setForm(f => ({ ...f, type: e.target.value as VideoForm["type"], videoId: "", src: "", url: "", label: "" }))}><option value="embed">YouTube</option><option value="local">Lokales Video</option><option value="link">Externer Link</option></select></div>
        <div><label style={S.label}>Titel *</label><input style={S.input} value={form.title} onChange={e => set("title", e.target.value)} required /></div>
        <div><label style={S.label}>Beschreibung *</label><textarea style={{ ...S.textarea, minHeight: 70 }} value={form.description} onChange={e => set("description", e.target.value)} required /></div>
        {form.type === "embed" && <div><label style={S.label}>YouTube Video-ID</label><input style={S.input} value={form.videoId ?? ""} onChange={e => set("videoId", e.target.value)} placeholder="dQw4w9WgXcQ" /></div>}
        {form.type === "local" && <div><label style={S.label}>Video-Pfad</label><input style={S.input} value={form.src ?? ""} onChange={e => set("src", e.target.value)} placeholder="/videos/..." /></div>}
        {form.type === "link" && <>
          <div><label style={S.label}>URL</label><input style={S.input} value={form.url ?? ""} onChange={e => set("url", e.target.value)} /></div>
          <div><label style={S.label}>Button-Text</label><input style={S.input} value={form.label ?? ""} onChange={e => set("label", e.target.value)} /></div>
        </>}
        <FormActions loading={loading} onClose={onClose} />
      </form>
    </Modal>
  );
}

function VideoManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [items, setItems] = useState<VideoItem[]>([]); const [modal, setModal] = useState<{ open: boolean; editing: VideoItem | null }>({ open: false, editing: null });
  const load = useCallback(async () => { try { setItems(await apiFetch("/api/admin/videos")); } catch { toast("Fehler", "err"); } }, [toast]);
  useEffect(() => { load(); }, [load]);
  async function save(data: VideoForm) {
    if (modal.editing) { await apiFetch(`/api/admin/videos/${modal.editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Aktualisiert"); }
    else { await apiFetch("/api/admin/videos", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Hinzugefügt"); }
    await load();
  }
  async function del(id: string) { if (!confirm("Löschen?")) return; await apiFetch(`/api/admin/videos/${id}`, { method: "DELETE" }); toast("Gelöscht"); await load(); }
  async function move(id: string, dir: -1 | 1) {
    const sorted = [...items].sort((a, b) => a.order - b.order); const idx = sorted.findIndex(v => v.id === id); const swap = idx + dir;
    if (swap < 0 || swap >= sorted.length) return;
    await apiFetch("/api/admin/videos", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify([{ id: sorted[idx].id, order: sorted[swap].order }, { id: sorted[swap].id, order: sorted[idx].order }]) });
    await load();
  }
  const sorted = [...items].sort((a, b) => a.order - b.order);
  const typeLabel: Record<string, string> = { embed: "YouTube", local: "Lokal", link: "Link" };
  return (
    <div>
      <div style={{ ...S.row, marginBottom: 20 }}><h2 style={{ margin: 0, fontSize: 20 }}>Lehrfilme</h2><button style={S.btn} onClick={() => setModal({ open: true, editing: null })}>+ Video hinzufügen</button></div>
      {sorted.map((item, i) => (
        <div key={item.id} style={S.card}>
          <div style={S.row}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: "flex", gap: 8, marginBottom: 4 }}><span style={S.badgeInfo}>{typeLabel[item.type] ?? item.type}</span><span style={{ color: "#8a8680", fontSize: 11 }}>#{i + 1}</span></div>
              <div style={{ fontWeight: 600, fontSize: 15, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.title}</div>
              <div style={{ fontSize: 12, color: "#8a8680", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.type === "embed" ? `youtube.com/watch?v=${item.videoId}` : item.type === "local" ? item.src : item.url}</div>
            </div>
            <div style={S.actions}>
              <button style={S.btnGhost} disabled={i === 0} onClick={() => move(item.id, -1)}>↑</button>
              <button style={S.btnGhost} disabled={i === sorted.length - 1} onClick={() => move(item.id, 1)}>↓</button>
              <button style={S.btnSm} onClick={() => setModal({ open: true, editing: item })}>Bearbeiten</button>
              <button style={S.btnDanger} onClick={() => del(item.id)}>Löschen</button>
            </div>
          </div>
        </div>
      ))}
      {modal.open && <VideoModal initial={modal.editing ? { type: modal.editing.type, title: modal.editing.title, description: modal.editing.description, videoId: modal.editing.videoId, src: modal.editing.src, url: modal.editing.url, label: modal.editing.label, compact: modal.editing.compact } : emptyVideo()} onSave={save} onClose={() => setModal({ open: false, editing: null })} />}
    </div>
  );
}

// ─── Holidays ─────────────────────────────────────────────────────────────────

type HolidayForm = Omit<HolidayPeriod, "id" | "order">;
const emptyHoliday = (): HolidayForm => ({ label: "", dates: "", note: "" });

function HolidayModal({ initial, onSave, onClose }: { initial: HolidayForm; onSave: (d: HolidayForm) => Promise<void>; onClose: () => void }) {
  const [form, setForm] = useState(initial); const [loading, setLoading] = useState(false);
  async function submit(e: React.FormEvent) { e.preventDefault(); setLoading(true); try { await onSave(form); onClose(); } finally { setLoading(false); } }
  return (
    <Modal title={initial.label ? "Eintrag bearbeiten" : "Ferieneintrag hinzufügen"} onClose={onClose}>
      <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        <div><label style={S.label}>Bezeichnung *</label><input style={S.input} value={form.label} onChange={e => setForm(f => ({ ...f, label: e.target.value }))} required placeholder="z. B. Herbstferien 2025" /></div>
        <div><label style={S.label}>Datum / Zeitraum *</label><input style={S.input} value={form.dates} onChange={e => setForm(f => ({ ...f, dates: e.target.value }))} required placeholder="z. B. 4. Oktober – 17. Oktober 2025" /></div>
        <div><label style={S.label}>Hinweis (optional)</label><input style={S.input} value={form.note ?? ""} onChange={e => setForm(f => ({ ...f, note: e.target.value }))} placeholder="kein Training" /></div>
        <FormActions loading={loading} onClose={onClose} />
      </form>
    </Modal>
  );
}

function HolidaysManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [items, setItems] = useState<HolidayPeriod[]>([]); const [modal, setModal] = useState<{ open: boolean; editing: HolidayPeriod | null }>({ open: false, editing: null });
  const load = useCallback(async () => { try { setItems(await apiFetch("/api/admin/holidays")); } catch { toast("Fehler", "err"); } }, [toast]);
  useEffect(() => { load(); }, [load]);
  async function save(data: HolidayForm) {
    if (modal.editing) { await apiFetch(`/api/admin/holidays/${modal.editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Aktualisiert"); }
    else { await apiFetch("/api/admin/holidays", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); toast("Hinzugefügt"); }
    await load();
  }
  async function del(id: string) { if (!confirm("Löschen?")) return; await apiFetch(`/api/admin/holidays/${id}`, { method: "DELETE" }); toast("Gelöscht"); await load(); }
  return (
    <div>
      <div style={{ ...S.row, marginBottom: 8 }}><h2 style={{ margin: 0, fontSize: 20 }}>Ferien &amp; Feiertage</h2><button style={S.btn} onClick={() => setModal({ open: true, editing: null })}>+ Eintrag</button></div>
      <p style={{ fontSize: 12, color: "#8a8680", marginBottom: 20 }}>Erscheint auf <code>/verein/ferien-feiertage</code>.</p>
      {items.map(item => (
        <div key={item.id} style={S.card}>
          <div style={S.row}>
            <div>
              <div style={{ fontWeight: 600 }}>{item.label}</div>
              <div style={{ fontSize: 13, color: "#8a8680" }}>{item.dates}</div>
              {item.note && <div style={{ fontSize: 12, color: "#555", fontStyle: "italic" }}>{item.note}</div>}
            </div>
            <div style={S.actions}>
              <button style={S.btnSm} onClick={() => setModal({ open: true, editing: item })}>Bearbeiten</button>
              <button style={S.btnDanger} onClick={() => del(item.id)}>Löschen</button>
            </div>
          </div>
        </div>
      ))}
      {modal.open && <HolidayModal initial={modal.editing ? { label: modal.editing.label, dates: modal.editing.dates, note: modal.editing.note ?? "" } : emptyHoliday()} onSave={save} onClose={() => setModal({ open: false, editing: null })} />}
    </div>
  );
}

// ─── Security ─────────────────────────────────────────────────────────────────

function SecurityManager({ toast, totpEnabled, weakPassword, onTotpChange }: { toast: (m: string, t?: "ok" | "err") => void; totpEnabled: boolean; weakPassword: boolean; onTotpChange: (e: boolean) => void }) {
  const [totp2FAState, setTotp2FAState] = useState<"idle" | "setup" | "disable">("idle");
  const [qrSvg, setQrSvg] = useState(""); const [totpSecret, setTotpSecret] = useState(""); const [totpCode, setTotpCode] = useState(""); const [disablePw, setDisablePw] = useState(""); const [totpLoading, setTotpLoading] = useState(false);
  const [pwForm, setPwForm] = useState({ current: "", new: "", confirm: "" }); const [pwLoading, setPwLoading] = useState(false);
  const [audit, setAudit] = useState<AuditEntry[]>([]);
  const [tokenStatus, setTokenStatus] = useState<InviteTokenStatus | null>(null);
  const [tokenLoading, setTokenLoading] = useState(false);

  useEffect(() => {
    apiFetch("/api/admin/audit").then(setAudit).catch(() => {});
    apiFetch("/api/admin/invite-token").then(setTokenStatus).catch(() => {});
    // Pseudo-cron: max 1× pro Tag — prüft ob Token bald abläuft
    apiFetch("/api/admin/invite-token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "cron" }) })
      .then(() => apiFetch("/api/admin/invite-token").then(setTokenStatus))
      .catch(() => {});
  }, []);

  const pwStrength = (() => { const p = pwForm.new; if (!p) return null; if (p.length < 8) return { label: "Sehr schwach", color: "#f44" }; if (p.length < 12) return { label: "Schwach (min. 12)", color: "#f84" }; const has = [/[A-Z]/, /[a-z]/, /[0-9]/, /[^A-Za-z0-9]/].filter(r => r.test(p)).length; if (has < 2) return { label: "Mittel", color: "#fb0" }; if (has < 3) return { label: "Gut", color: "#9d0" }; return { label: "Stark", color: "#6f6" }; })();

  async function startTotpSetup() { setTotpLoading(true); try { const data = await apiFetch("/api/admin/totp/setup"); setQrSvg(data.qrSvg); setTotpSecret(data.secret); setTotpCode(""); setTotp2FAState("setup"); } catch (ex: unknown) { toast(ex instanceof Error ? ex.message : "Fehler", "err"); } finally { setTotpLoading(false); } }
  async function confirmTotp() { setTotpLoading(true); try { await apiFetch("/api/admin/totp/confirm", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ code: totpCode }) }); toast("2FA aktiviert!"); setTotp2FAState("idle"); onTotpChange(true); } catch (ex: unknown) { toast(ex instanceof Error ? ex.message : "Fehler", "err"); } finally { setTotpLoading(false); } }
  async function disableTotp() { setTotpLoading(true); try { await apiFetch("/api/admin/totp/disable", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ password: disablePw }) }); toast("2FA deaktiviert"); setTotp2FAState("idle"); setDisablePw(""); onTotpChange(false); } catch (ex: unknown) { toast(ex instanceof Error ? ex.message : "Fehler", "err"); } finally { setTotpLoading(false); } }
  async function changePassword(e: React.FormEvent) { e.preventDefault(); setPwLoading(true); try { await apiFetch("/api/admin/password", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ currentPassword: pwForm.current, newPassword: pwForm.new, confirmPassword: pwForm.confirm }) }); toast("Passwort geändert!"); setPwForm({ current: "", new: "", confirm: "" }); } catch (ex: unknown) { toast(ex instanceof Error ? ex.message : "Fehler", "err"); } finally { setPwLoading(false); } }
  async function rotateInviteToken() {
    setTokenLoading(true);
    try {
      const data = await apiFetch("/api/admin/invite-token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "rotate" }) });
      toast(data.message ?? "Token erneuert", "ok");
      apiFetch("/api/admin/invite-token").then(setTokenStatus).catch(() => {});
    } catch (ex: unknown) { toast(ex instanceof Error ? ex.message : "Fehler", "err"); }
    finally { setTokenLoading(false); }
  }
  const actionColor = (a: string) => a.includes("FAIL") || a.includes("BLOCKED") ? "#f88" : a.includes("SUCCESS") || a.includes("CHANGED") || a.includes("ENABLED") ? "#6f6" : "#8a8680";

  return (
    <div>
      <h2 style={{ margin: "0 0 20px", fontSize: 20 }}>Sicherheit</h2>
      <div style={S.secCard}>
        <h3 style={{ margin: "0 0 12px", fontSize: 15, fontWeight: 700 }}>Status</h3>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 10 }}>
          <span>2FA: <span style={totpEnabled ? S.badgeOk : S.badgeDanger}>{totpEnabled ? "✓ Aktiv" : "✗ Inaktiv"}</span></span>
          <span>Passwort: <span style={weakPassword ? S.badgeDanger : S.badgeOk}>{weakPassword ? "⚠ Standard" : "✓ Geändert"}</span></span>
          <span>Cookie: <span style={S.badgeOk}>httpOnly · Strict</span></span>
          <span>Brute-Force: <span style={S.badgeOk}>✓ 5/15min</span></span>
        </div>
      </div>
      <div style={S.secCard}>
        <h3 style={{ margin: "0 0 12px", fontSize: 15, fontWeight: 700 }}>2FA (TOTP)</h3>
        {totp2FAState === "idle" && (<>
          <p style={{ fontSize: 13, color: "#8a8680", marginBottom: 12 }}>{totpEnabled ? "2FA ist aktiv (Google Authenticator / Authy)." : "2FA aktivieren für maximalen Schutz."}</p>
          {totpEnabled ? <button style={S.btnDanger} onClick={() => setTotp2FAState("disable")}>2FA deaktivieren</button> : <button style={S.btn} onClick={startTotpSetup} disabled={totpLoading}>{totpLoading ? "…" : "2FA aktivieren"}</button>}
        </>)}
        {totp2FAState === "setup" && (<div>
          <p style={{ fontSize: 13, color: "#8a8680", marginBottom: 12 }}>QR-Code mit Authenticator-App scannen, dann Code eingeben:</p>
          <div style={{ background: "#fff", display: "inline-block", padding: 10, borderRadius: 8, marginBottom: 10 }} dangerouslySetInnerHTML={{ __html: qrSvg }} />
          <p style={{ fontSize: 11, color: "#8a8680", marginBottom: 10, wordBreak: "break-all" }}>Manuell: <code style={{ color: "#e8e4df" }}>{totpSecret}</code></p>
          <div style={{ display: "flex", gap: 8 }}>
            <input type="text" value={totpCode} onChange={e => setTotpCode(e.target.value.replace(/\D/g, ""))} maxLength={6} inputMode="numeric" style={{ ...S.input, maxWidth: 140, letterSpacing: "0.2em", fontSize: 20 }} placeholder="000000" />
            <button style={S.btn} onClick={confirmTotp} disabled={totpLoading || totpCode.length !== 6}>{totpLoading ? "…" : "Bestätigen"}</button>
            <button style={S.btnGhost} onClick={() => setTotp2FAState("idle")}>Abbrechen</button>
          </div>
        </div>)}
        {totp2FAState === "disable" && (<div>
          <p style={{ fontSize: 13, color: "#f88", marginBottom: 12 }}>Passwort zur Bestätigung eingeben:</p>
          <div style={{ display: "flex", gap: 8 }}>
            <input type="password" value={disablePw} onChange={e => setDisablePw(e.target.value)} style={{ ...S.input, maxWidth: 240 }} />
            <button style={S.btnDanger} onClick={disableTotp} disabled={totpLoading || !disablePw}>{totpLoading ? "…" : "Deaktivieren"}</button>
            <button style={S.btnGhost} onClick={() => setTotp2FAState("idle")}>Abbrechen</button>
          </div>
        </div>)}
      </div>
      <div style={S.secCard}>
        <h3 style={{ margin: "0 0 12px", fontSize: 15, fontWeight: 700 }}>Invite-Token</h3>
        {!tokenStatus ? (
          <p style={{ color: "#8a8680", fontSize: 13 }}>Lade…</p>
        ) : (
          <>
            <div style={{ display: "flex", flexWrap: "wrap" as const, gap: 10, marginBottom: 12 }}>
              <span>Status: <span style={tokenStatus.status === "ok" ? S.badgeOk : tokenStatus.status === "warning" ? S.badgeWarn : S.badgeDanger}>{tokenStatus.status === "ok" ? "✓ Gültig" : tokenStatus.status === "warning" ? `⚠ ${tokenStatus.daysLeft}d verbleibend` : "✗ Abgelaufen"}</span></span>
              <span style={{ color: "#8a8680", fontSize: 13 }}>Läuft ab: {new Date(tokenStatus.expiresAt).toLocaleDateString("de-CH")}</span>
              {tokenStatus.lastCronCheck && <span style={{ color: "#8a8680", fontSize: 13 }}>Letzte Prüfung: {tokenStatus.lastCronCheck}</span>}
            </div>
            {(() => {
              const total = Math.round((new Date(tokenStatus.expiresAt).getTime() - new Date(tokenStatus.createdAt).getTime()) / (24 * 60 * 60 * 1000));
              const used = total - Math.max(0, tokenStatus.daysLeft);
              const pct = Math.min(100, Math.round((used / total) * 100));
              const barColor = tokenStatus.status === "ok" ? "#4a9a4a" : tokenStatus.status === "warning" ? "#c88000" : "#8B0000";
              return (
                <div style={{ marginBottom: 12 }}>
                  <div style={{ height: 6, background: "#2a2a2a", borderRadius: 3, overflow: "hidden" }}>
                    <div style={{ height: "100%", width: `${pct}%`, background: barColor, borderRadius: 3, transition: "width 0.3s" }} />
                  </div>
                  <div style={{ fontSize: 11, color: "#8a8680", marginTop: 4 }}>{used} von {total} Tagen verwendet</div>
                </div>
              );
            })()}
            {tokenStatus.status !== "ok" && (
              <p style={{ fontSize: 12, color: tokenStatus.status === "expired" ? "#f88" : "#fb0", marginBottom: 12 }}>
                {tokenStatus.status === "expired" ? "Token abgelaufen. Erneuere es — du erhältst per E-Mail einen neuen Link. Danach Server neu starten." : `Token läuft in ${tokenStatus.daysLeft} Tagen ab. Eine Vorwarn-E-Mail wurde gesendet.`}
              </p>
            )}
            <button style={S.btn} onClick={rotateInviteToken} disabled={tokenLoading}>{tokenLoading ? "…" : "Token jetzt erneuern"}</button>
            <p style={{ fontSize: 11, color: "#8a8680", marginTop: 8 }}>Nach der Erneuerung: Server neu starten und Link aus der E-Mail verwenden.</p>
          </>
        )}
      </div>
      <div style={S.secCard}>
        <h3 style={{ margin: "0 0 8px", fontSize: 15, fontWeight: 700 }}>Passwort ändern</h3>
        <p style={{ fontSize: 12, color: "#8a8680", marginBottom: 14 }}>Min. 12 Zeichen · HaveIBeenPwned-geprüft</p>
        <form onSubmit={changePassword} style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          <div><label style={S.label}>Aktuelles Passwort</label><input type="password" value={pwForm.current} onChange={e => setPwForm(f => ({ ...f, current: e.target.value }))} style={{ ...S.input, maxWidth: 320 }} required /></div>
          <div><label style={S.label}>Neues Passwort</label><input type="password" value={pwForm.new} onChange={e => setPwForm(f => ({ ...f, new: e.target.value }))} style={{ ...S.input, maxWidth: 320 }} required minLength={12} />{pwStrength && <div style={{ fontSize: 11, color: pwStrength.color, marginTop: 4 }}>Stärke: {pwStrength.label}</div>}</div>
          <div><label style={S.label}>Wiederholen</label><input type="password" value={pwForm.confirm} onChange={e => setPwForm(f => ({ ...f, confirm: e.target.value }))} style={{ ...S.input, maxWidth: 320 }} required />{pwForm.confirm && pwForm.new !== pwForm.confirm && <div style={{ fontSize: 11, color: "#f88", marginTop: 4 }}>Stimmt nicht überein</div>}</div>
          <button type="submit" disabled={pwLoading || pwForm.new !== pwForm.confirm || pwForm.new.length < 12} style={{ ...S.btn, width: "fit-content" }}>{pwLoading ? "Ändern…" : "Passwort ändern"}</button>
        </form>
      </div>
      <div style={S.secCard}>
        <h3 style={{ margin: "0 0 12px", fontSize: 15, fontWeight: 700 }}>Aktivitätsprotokoll</h3>
        {audit.length === 0 ? <p style={{ color: "#8a8680", fontSize: 13 }}>Noch keine Einträge.</p> : (
          <div style={{ overflowX: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
              <thead><tr style={{ borderBottom: "1px solid #2a2a2a" }}>{["Zeit", "IP", "Aktion", "Detail"].map(h => <th key={h} style={{ padding: "6px 10px", textAlign: "left", color: "#8a8680", fontWeight: 600 }}>{h}</th>)}</tr></thead>
              <tbody>{audit.map((e, i) => (<tr key={i} style={{ borderBottom: "1px solid #1a1a1a" }}>
                <td style={{ padding: "5px 10px", color: "#8a8680", whiteSpace: "nowrap" }}>{new Date(e.ts).toLocaleString("de-CH")}</td>
                <td style={{ padding: "5px 10px", fontFamily: "monospace", color: "#8a8680" }}>{e.ip}</td>
                <td style={{ padding: "5px 10px", color: actionColor(e.action), fontWeight: 600 }}>{e.action}</td>
                <td style={{ padding: "5px 10px", color: "#8a8680" }}>{e.detail}</td>
              </tr>))}</tbody>
            </table>
          </div>
        )}
      </div>
    </div>
  );
}

// ─── ContactsManager ─────────────────────────────────────────────────────────

function ContactsManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [contacts, setContacts] = useState<ContactSubmission[]>([]);
  const [filter, setFilter] = useState<"ungelesen" | "alle" | "archiviert">("ungelesen");
  const [selected, setSelected] = useState<ContactSubmission | null>(null);

  const load = useCallback(async () => { const d = await apiFetch("/api/admin/contacts"); setContacts(d); }, []);
  useEffect(() => { load(); }, [load]);

  const markRead = async (id: string) => {
    await apiFetch(`/api/admin/contacts/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ isRead: true }) });
    await load();
  };
  const archive = async (id: string) => {
    await apiFetch(`/api/admin/contacts/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ isArchived: true }) });
    await load(); setSelected(null);
  };
  const del = async (id: string) => {
    await apiFetch(`/api/admin/contacts/${id}`, { method: "DELETE" });
    await load(); setSelected(null); toast("Gelöscht");
  };

  const visible = contacts.filter(c => filter === "archiviert" ? c.isArchived : filter === "ungelesen" ? !c.isRead && !c.isArchived : !c.isArchived);
  const unreadCount = contacts.filter(c => !c.isRead && !c.isArchived).length;

  return (
    <div>
      <div style={S.row}>
        <h2 style={{ color: "#e8e4df", fontSize: 20, fontWeight: 600 }}>Anfragen {unreadCount > 0 && <span style={{ ...S.badgeDanger, marginLeft: 8 }}>{unreadCount} neu</span>}</h2>
        <div style={{ display: "flex", gap: 6 }}>
          {(["ungelesen", "alle", "archiviert"] as const).map(f => (
            <button key={f} style={filter === f ? S.btnSm : S.btnGhost} onClick={() => setFilter(f)}>
              {f === "ungelesen" ? "Ungelesen" : f === "alle" ? "Alle" : "Archiv"}
            </button>
          ))}
        </div>
      </div>
      <div style={{ marginTop: 16 }}>
        {visible.length === 0 && <p style={{ color: "#8a8680", fontSize: 14 }}>Keine Anfragen</p>}
        {visible.map(c => (
          <div key={c.id} style={{ ...S.card, borderLeft: `3px solid ${c.isRead ? "#2a2a2a" : "#8B0000"}`, cursor: "pointer" }}
            onClick={async () => { setSelected(c); if (!c.isRead) await markRead(c.id); }}>
            <div style={S.row}>
              <div>
                <strong style={{ fontSize: 14 }}>{c.name}</strong>
                {!c.isRead && <span style={{ ...S.badgeDanger, marginLeft: 8 }}>NEU</span>}
                <span style={{ ...S.badgeInfo, marginLeft: 6 }}>{c.typ}</span>
                {c.alterYears && <span style={{ ...S.badgeOk, marginLeft: 4 }}>{c.alterYears}</span>}
              </div>
              <span style={{ color: "#8a8680", fontSize: 12 }}>{fmtDate(c.submittedAt)}</span>
            </div>
            <div style={{ color: "#8a8680", fontSize: 13, marginTop: 4 }}>{c.email}{c.phone ? ` · ${c.phone}` : ""}</div>
            {c.nachricht && <div style={{ color: "#b0aa9e", fontSize: 13, marginTop: 6 }}>{c.nachricht.slice(0, 120)}{c.nachricht.length > 120 ? "…" : ""}</div>}
          </div>
        ))}
      </div>
      {selected && (
        <div style={S.modal} onClick={() => setSelected(null)}>
          <div style={S.modalBox} onClick={e => e.stopPropagation()}>
            <div style={S.row}>
              <h3 style={{ color: "#e8e4df", fontSize: 16, fontWeight: 600 }}>{selected.name}</h3>
              <button style={S.btnGhost} onClick={() => setSelected(null)}>✕</button>
            </div>
            <div style={{ marginTop: 12, display: "flex", flexDirection: "column", gap: 10 }}>
              <div><span style={S.label}>Interesse</span><span style={S.badgeInfo}>{selected.typ}</span></div>
              {selected.alterYears && <div><span style={S.label}>Altersgruppe</span><span style={{ fontSize: 14 }}>{selected.alterYears}</span></div>}
              <div><span style={S.label}>E-Mail</span><a href={`mailto:${selected.email}`} style={{ color: "#8B0000" }}>{selected.email}</a></div>
              {selected.phone && <div><span style={S.label}>Telefon</span><span style={{ fontSize: 14 }}>{selected.phone}</span></div>}
              {selected.nachricht && <div><span style={S.label}>Nachricht</span><div style={{ color: "#b0aa9e", whiteSpace: "pre-wrap", fontSize: 14, marginTop: 4 }}>{selected.nachricht}</div></div>}
              <div><span style={S.label}>Eingegangen</span><span style={{ fontSize: 14 }}>{fmtDate(selected.submittedAt)}</span></div>
            </div>
            <div style={{ ...S.actions, marginTop: 16 }}>
              <a href={`mailto:${selected.email}?subject=Ihre Anfrage beim JKA-Karateclub Arbon`} style={{ ...S.btn, textDecoration: "none", fontSize: 13, display: "inline-block" }}>✉ Antworten</a>
              {!selected.isArchived && <button style={S.btnGhost} onClick={() => archive(selected.id)}>Archivieren</button>}
              <button style={S.btnDanger} onClick={() => del(selected.id)}>Löschen</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── MitgliederManager ────────────────────────────────────────────────────────

const GÜRTELGRADE = ["9. Kyu","8. Kyu","7. Kyu","6. Kyu","5. Kyu","4. Kyu","3. Kyu","2. Kyu","1. Kyu","1. Dan","2. Dan","3. Dan","4. Dan","5. Dan"];

function MitgliederManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [mitglieder, setMitglieder] = useState<Mitglied[]>([]);
  const [editing, setEditing] = useState<Mitglied | null>(null);
  const [isNew, setIsNew] = useState(false);
  const [filter, setFilter] = useState<"aktiv" | "alle" | "inaktiv">("aktiv");
  const emptyM = (): Mitglied => ({ id: "", name: "", email: "", phone: "", geburtsdatum: "", eintrittsdatum: new Date().toISOString().slice(0, 10), gürtelgrad: "9. Kyu", aktiv: true, notizen: "", imageUrl: "" });
  const imgRef = useRef<HTMLInputElement>(null);
  const [imgUploading, setImgUploading] = useState(false);

  const load = useCallback(async () => { const d = await apiFetch("/api/admin/mitglieder"); setMitglieder(d); }, []);
  useEffect(() => { load(); }, [load]);

  const save = async () => {
    if (!editing) return;
    try {
      if (isNew) { await apiFetch("/api/admin/mitglieder", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...editing, id: newId() }) }); toast("Mitglied hinzugefügt"); }
      else { await apiFetch(`/api/admin/mitglieder/${editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(editing) }); toast("Gespeichert"); }
      await load(); setEditing(null);
    } catch (e: unknown) { toast((e as Error).message, "err"); }
  };
  const del = async (id: string) => {
    try { await apiFetch(`/api/admin/mitglieder/${id}`, { method: "DELETE" }); await load(); toast("Gelöscht"); } catch (e: unknown) { toast((e as Error).message, "err"); }
  };

  const visible = mitglieder.filter(m => filter === "alle" || (filter === "aktiv" ? m.aktiv : !m.aktiv));

  return (
    <div>
      <div style={S.row}>
        <h2 style={{ color: "#e8e4df", fontSize: 20, fontWeight: 600 }}>
          Mitglieder <span style={{ ...S.badgeOk, marginLeft: 8 }}>{mitglieder.filter(m => m.aktiv).length} aktiv</span>
        </h2>
        <div style={{ display: "flex", gap: 6 }}>
          {(["aktiv", "alle", "inaktiv"] as const).map(f => (
            <button key={f} style={filter === f ? S.btnSm : S.btnGhost} onClick={() => setFilter(f)}>{f.charAt(0).toUpperCase() + f.slice(1)}</button>
          ))}
          <button style={S.btn} onClick={() => { setIsNew(true); setEditing(emptyM()); }}>+ Mitglied</button>
        </div>
      </div>
      <div style={{ ...S.secCard, marginTop: 16 }}>
        {visible.length === 0 && <p style={{ color: "#8a8680", fontSize: 13, margin: 0 }}>Keine Einträge</p>}
        {visible.map((m, i) => (
          <div key={m.id} style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px 0", borderBottom: i < visible.length - 1 ? "1px solid #1f1f1f" : "none", opacity: m.aktiv ? 1 : 0.5 }}>
            {m.imageUrl
              ? <img src={m.imageUrl} alt={m.name} style={{ width: 32, height: 32, borderRadius: "50%", objectFit: "cover", flexShrink: 0 }} />
              : <div style={{ width: 32, height: 32, borderRadius: "50%", background: "#2a2a2a", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 13, flexShrink: 0 }}>🥋</div>
            }
            <div style={{ flex: 1, minWidth: 0 }}>
              <span style={{ fontWeight: 600, fontSize: 13 }}>{m.name}</span>
              {!m.aktiv && <span style={{ ...S.badgeWarn, marginLeft: 6, fontSize: 10 }}>Inaktiv</span>}
              {m.email && <span style={{ color: "#8a8680", fontSize: 11, marginLeft: 8 }}>{m.email}</span>}
            </div>
            <span style={{ ...S.badgeInfo, fontSize: 10, flexShrink: 0 }}>{m.gürtelgrad}</span>
            <div style={{ display: "flex", gap: 4, flexShrink: 0 }}>
              <button style={{ ...S.btnSm, fontSize: 11, padding: "3px 8px" }} onClick={() => { setIsNew(false); setEditing({ ...m }); }}>Bearbeiten</button>
              <button style={{ ...S.btnDanger, fontSize: 11, padding: "3px 6px" }} onClick={() => del(m.id)}>×</button>
            </div>
          </div>
        ))}
      </div>
      {editing && (
        <Modal title={isNew ? "Neues Mitglied" : "Mitglied bearbeiten"} onClose={() => setEditing(null)}>
          <div style={{ display: "flex", alignItems: "center", gap: 16, marginBottom: 16 }}>
            {editing.imageUrl
              ? <img src={editing.imageUrl} alt="" style={{ width: 64, height: 64, borderRadius: "50%", objectFit: "cover" }} />
              : <div style={{ width: 64, height: 64, borderRadius: "50%", background: "#2a2a2a", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 24 }}>🥋</div>
            }
            <div>
              <input type="file" accept="image/*" ref={imgRef} style={{ display: "none" }} onChange={async e => {
                const file = e.target.files?.[0]; if (!file) return;
                setImgUploading(true);
                try {
                  const fd = new FormData(); fd.append("file", file);
                  const res = await fetch("/api/admin/upload", { method: "POST", credentials: "include", body: fd });
                  const json = await res.json();
                  if (!res.ok) throw new Error(json.error);
                  setEditing(prev => prev ? { ...prev, imageUrl: json.src } : prev);
                } catch (e: unknown) { toast((e as Error).message, "err"); }
                setImgUploading(false);
              }} />
              <button style={S.btnGhost} onClick={() => imgRef.current?.click()} disabled={imgUploading}>
                {imgUploading ? "Lädt…" : editing.imageUrl ? "Foto ändern" : "Foto hochladen"}
              </button>
              {editing.imageUrl && <button style={{ ...S.btnGhost, marginLeft: 6, fontSize: 12 }} onClick={() => setEditing({ ...editing, imageUrl: "" })}>Entfernen</button>}
            </div>
          </div>
          <label style={S.label}>Name *</label>
          <input style={S.input} value={editing.name} onChange={e => setEditing({ ...editing, name: e.target.value })} />
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 12 }}>
            <div><label style={S.label}>E-Mail</label><input style={S.input} type="email" value={editing.email ?? ""} onChange={e => setEditing({ ...editing, email: e.target.value })} /></div>
            <div><label style={S.label}>Telefon</label><input style={S.input} value={editing.phone ?? ""} onChange={e => setEditing({ ...editing, phone: e.target.value })} /></div>
            <div><label style={S.label}>Geburtsdatum</label><input style={S.input} type="date" value={editing.geburtsdatum ?? ""} onChange={e => setEditing({ ...editing, geburtsdatum: e.target.value })} /></div>
            <div><label style={S.label}>Eintrittsdatum</label><input style={S.input} type="date" value={editing.eintrittsdatum} onChange={e => setEditing({ ...editing, eintrittsdatum: e.target.value })} /></div>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 12 }}>
            <div>
              <label style={S.label}>Gürtelgrad</label>
              <select style={S.select} value={editing.gürtelgrad} onChange={e => setEditing({ ...editing, gürtelgrad: e.target.value })}>
                {GÜRTELGRADE.map(g => <option key={g}>{g}</option>)}
              </select>
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 8, paddingTop: 20 }}>
              <input type="checkbox" id="m-aktiv" checked={editing.aktiv} onChange={e => setEditing({ ...editing, aktiv: e.target.checked })} />
              <label htmlFor="m-aktiv" style={{ color: "#e8e4df", fontSize: 14 }}>Aktives Mitglied</label>
            </div>
          </div>
          <div style={{ marginTop: 12 }}>
            <label style={S.label}>Notizen</label>
            <textarea style={S.textarea} value={editing.notizen ?? ""} onChange={e => setEditing({ ...editing, notizen: e.target.value })} />
          </div>
          <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 16 }}>
            <button type="button" style={S.btnGhost} onClick={() => setEditing(null)}>Abbrechen</button>
            <button type="button" style={S.btn} onClick={save}>Speichern</button>
          </div>
        </Modal>
      )}
    </div>
  );
}

// ─── DokumenteManager ─────────────────────────────────────────────────────────

function DokumenteManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [dokumente, setDokumente] = useState<Dokument[]>([]);
  const [editing, setEditing] = useState<Partial<Dokument> | null>(null);
  const [isNew, setIsNew] = useState(false);
  const [uploading, setUploading] = useState(false);
  const fileRef = useRef<HTMLInputElement>(null);

  const load = useCallback(async () => { const d = await apiFetch("/api/admin/dokumente"); setDokumente(d); }, []);
  useEffect(() => { load(); }, [load]);

  const handleUpload = async (file: File) => {
    setUploading(true);
    try {
      const fd = new FormData(); fd.append("file", file);
      const res = await fetch("/api/admin/upload-doc", { method: "POST", credentials: "include", body: fd });
      const json = await res.json();
      if (!res.ok) throw new Error(json.error);
      setEditing(prev => prev ? { ...prev, src: json.src, dateiname: file.name } : prev);
    } catch (e: unknown) { toast((e as Error).message, "err"); }
    setUploading(false);
  };

  const save = async () => {
    if (!editing?.titel || !editing?.src) { toast("Titel und Datei sind erforderlich", "err"); return; }
    try {
      const payload = { ...editing, kategorie: editing.kategorie ?? "Sonstiges", oeffentlich: editing.oeffentlich ?? false };
      if (isNew) { await apiFetch("/api/admin/dokumente", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...payload, id: newId(), uploadedAt: new Date().toISOString(), order: dokumente.length }) }); toast("Dokument hinzugefügt"); }
      else { await apiFetch(`/api/admin/dokumente/${editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); toast("Gespeichert"); }
      await load(); setEditing(null);
    } catch (e: unknown) { toast((e as Error).message, "err"); }
  };

  const del = async (id: string) => {
    try { await apiFetch(`/api/admin/dokumente/${id}`, { method: "DELETE" }); await load(); toast("Gelöscht"); } catch (e: unknown) { toast((e as Error).message, "err"); }
  };

  return (
    <div>
      <div style={S.row}>
        <h2 style={{ color: "#e8e4df", fontSize: 20, fontWeight: 600 }}>Dokumente</h2>
        <button style={S.btn} onClick={() => { setIsNew(true); setEditing({ titel: "", beschreibung: "", src: "", dateiname: "", kategorie: "Vereinsdokumente", oeffentlich: false }); }}>+ Dokument</button>
      </div>
      <p style={{ color: "#8a8680", fontSize: 13, marginTop: 6 }}>Öffentliche Dokumente erscheinen auf <code style={{ color: "#8a8680" }}>/prufungen</code>.</p>
      <div style={{ marginTop: 16 }}>
        {dokumente.map(d => (
          <div key={d.id} style={S.card}>
            <div style={S.row}>
              <div>
                <strong style={{ fontSize: 14 }}>📄 {d.titel}</strong>
                <span style={{ ...S.badgeInfo, marginLeft: 8 }}>{d.kategorie}</span>
                {d.oeffentlich ? <span style={{ ...S.badgeOk, marginLeft: 6 }}>Öffentlich</span> : <span style={{ ...S.badgeWarn, marginLeft: 6 }}>Intern</span>}
                <div style={{ color: "#8a8680", fontSize: 12, marginTop: 2 }}>{d.dateiname}</div>
              </div>
              <div style={S.actions}>
                <a href={d.src} target="_blank" rel="noopener noreferrer" style={{ ...S.btnGhost, textDecoration: "none", fontSize: 12 }}>↗</a>
                <button style={S.btnSm} onClick={() => { setIsNew(false); setEditing({ ...d }); }}>Bearbeiten</button>
                <button style={S.btnDanger} onClick={() => del(d.id)}>×</button>
              </div>
            </div>
          </div>
        ))}
        {dokumente.length === 0 && <p style={{ color: "#8a8680", fontSize: 14 }}>Noch keine Dokumente</p>}
      </div>
      {editing && (
        <Modal title={isNew ? "Neues Dokument" : "Dokument bearbeiten"} onClose={() => setEditing(null)}>
          <label style={S.label}>Titel *</label>
          <input style={S.input} value={editing.titel ?? ""} onChange={e => setEditing({ ...editing, titel: e.target.value })} />
          <div style={{ marginTop: 12 }}>
            <label style={S.label}>Beschreibung</label>
            <input style={S.input} value={editing.beschreibung ?? ""} onChange={e => setEditing({ ...editing, beschreibung: e.target.value })} />
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginTop: 12 }}>
            <div>
              <label style={S.label}>Kategorie</label>
              <select style={S.select} value={editing.kategorie ?? "Sonstiges"} onChange={e => setEditing({ ...editing, kategorie: e.target.value })}>
                {["Vereinsdokumente","Formulare","Prüfungsordnung","Sonstiges"].map(k => <option key={k}>{k}</option>)}
              </select>
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: 8, paddingTop: 20 }}>
              <input type="checkbox" id="d-pub" checked={editing.oeffentlich ?? false} onChange={e => setEditing({ ...editing, oeffentlich: e.target.checked })} />
              <label htmlFor="d-pub" style={{ color: "#e8e4df", fontSize: 14 }}>Auf Website zeigen</label>
            </div>
          </div>
          <div style={{ marginTop: 12 }}>
            <label style={S.label}>PDF-Datei {editing.src ? "(vorhanden)" : "*"}</label>
            {editing.src && <div style={{ color: "#8a8680", fontSize: 12, marginBottom: 6 }}>{editing.dateiname}</div>}
            <input type="file" accept=".pdf,application/pdf" ref={fileRef} style={{ display: "none" }} onChange={e => { if (e.target.files?.[0]) handleUpload(e.target.files[0]); }} />
            <button style={S.btnGhost} onClick={() => fileRef.current?.click()} disabled={uploading}>
              {uploading ? "Lädt…" : editing.src ? "Andere Datei" : "PDF hochladen"}
            </button>
          </div>
          <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 16 }}>
            <button type="button" style={S.btnGhost} onClick={() => setEditing(null)}>Abbrechen</button>
            <button type="button" style={S.btn} onClick={save}>Speichern</button>
          </div>
        </Modal>
      )}
    </div>
  );
}

// ─── PruefungenManager ────────────────────────────────────────────────────────

function PruefungenManager({ toast }: { toast: (m: string, t?: "ok" | "err") => void }) {
  const [pruefungen, setPruefungen] = useState<Pruefung[]>([]);
  const [mitglieder, setMitglieder] = useState<Mitglied[]>([]);
  const [editing, setEditing] = useState<Pruefung | null>(null);
  const [isNew, setIsNew] = useState(false);
  const [detail, setDetail] = useState<Pruefung | null>(null);
  const emptyP = (): Pruefung => ({ id: "", datum: new Date().toISOString().slice(0, 10), ort: "Trainingshalle Arbon", prüfer: "", ergebnisse: [] });

  const load = useCallback(async () => {
    const [pd, md] = await Promise.all([apiFetch("/api/admin/pruefungen"), apiFetch("/api/admin/mitglieder").catch(() => [])]);
    setPruefungen(pd); setMitglieder(md);
  }, []);
  useEffect(() => { load(); }, [load]);

  const addErgebnis = () => {
    if (!editing || mitglieder.length === 0) return;
    const m = mitglieder[0];
    setEditing({ ...editing, ergebnisse: [...editing.ergebnisse, { mitgliedId: m.id, mitgliedName: m.name, vorherGrad: m.gürtelgrad, nachherGrad: m.gürtelgrad, bestanden: false }] });
  };

  const save = async () => {
    if (!editing) return;
    try {
      const hasPassed = editing.ergebnisse.some(e => e.bestanden);
      if (isNew) {
        const result = await apiFetch("/api/admin/pruefungen", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ...editing, id: newId() }) });
        toast(result.autoNewsId ? "Prüfung gespeichert & News-Beitrag erstellt ✓" : "Prüfung gespeichert");
      } else {
        const result = await apiFetch(`/api/admin/pruefungen/${editing.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(editing) });
        toast(hasPassed ? (result.autoNewsId ? "Gespeichert & News aktualisiert ✓" : "Gespeichert") : "Gespeichert");
      }
      await load(); setEditing(null);
    } catch (e: unknown) { toast((e as Error).message, "err"); }
  };

  const del = async (id: string) => {
    try { await apiFetch(`/api/admin/pruefungen/${id}`, { method: "DELETE" }); await load(); toast("Gelöscht"); setDetail(null); } catch (e: unknown) { toast((e as Error).message, "err"); }
  };

  return (
    <div>
      <div style={S.row}>
        <h2 style={{ color: "#e8e4df", fontSize: 20, fontWeight: 600 }}>Prüfungen</h2>
        <button style={S.btn} onClick={() => { setIsNew(true); setEditing(emptyP()); }}>+ Prüfung</button>
      </div>
      <div style={{ marginTop: 16 }}>
        {[...pruefungen].sort((a, b) => b.datum.localeCompare(a.datum)).map(p => (
          <div key={p.id} style={{ ...S.card, cursor: "pointer" }} onClick={() => setDetail(p)}>
            <div style={S.row}>
              <div>
                <strong style={{ fontSize: 14 }}>Kyū Shinsa — {fmtDate(p.datum)}</strong>
                <div style={{ color: "#8a8680", fontSize: 12, marginTop: 2 }}>{p.ort} · {p.ergebnisse.length} Teilnehmer · {p.ergebnisse.filter(e => e.bestanden).length} bestanden</div>
              </div>
              <div style={S.actions}>
                <button style={S.btnSm} onClick={ev => { ev.stopPropagation(); setIsNew(false); setEditing({ ...p, ergebnisse: [...p.ergebnisse] }); }}>Bearbeiten</button>
                <button style={S.btnDanger} onClick={ev => { ev.stopPropagation(); del(p.id); }}>×</button>
              </div>
            </div>
          </div>
        ))}
        {pruefungen.length === 0 && <p style={{ color: "#8a8680", fontSize: 14 }}>Noch keine Prüfungen erfasst</p>}
      </div>

      {detail && (
        <div style={S.modal} onClick={() => setDetail(null)}>
          <div style={{ ...S.modalBox, maxWidth: 680 }} onClick={e => e.stopPropagation()}>
            <div style={S.row}>
              <h3 style={{ color: "#e8e4df", fontSize: 16 }}>Kyū Shinsa — {fmtDate(detail.datum)}</h3>
              <button style={S.btnGhost} onClick={() => setDetail(null)}>✕</button>
            </div>
            <div style={{ color: "#8a8680", fontSize: 13, marginTop: 4 }}>{detail.ort}{detail.prüfer ? ` · Prüfer: ${detail.prüfer}` : ""}</div>
            <div style={{ overflowX: "auto", marginTop: 16 }}>
              <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
                <thead><tr style={{ borderBottom: "1px solid #2a2a2a", color: "#8a8680" }}>
                  <th style={{ textAlign: "left", padding: "6px 8px" }}>Name</th>
                  <th style={{ textAlign: "left", padding: "6px 8px" }}>Vorher</th>
                  <th style={{ textAlign: "left", padding: "6px 8px" }}>Nachher</th>
                  <th style={{ textAlign: "left", padding: "6px 8px" }}>Ergebnis</th>
                </tr></thead>
                <tbody>
                  {detail.ergebnisse.map((e, i) => (
                    <tr key={i} style={{ borderBottom: "1px solid #1e1e1e" }}>
                      <td style={{ padding: "8px" }}>{e.mitgliedName}</td>
                      <td style={{ padding: "8px", color: "#8a8680" }}>{e.vorherGrad}</td>
                      <td style={{ padding: "8px" }}>{e.nachherGrad}</td>
                      <td style={{ padding: "8px" }}><span style={e.bestanden ? S.badgeOk : S.badgeDanger}>{e.bestanden ? "Bestanden" : "Nicht bestanden"}</span></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      )}

      {editing && (
        <Modal title={isNew ? "Neue Prüfung" : "Prüfung bearbeiten"} onClose={() => setEditing(null)}>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            <div><label style={S.label}>Datum *</label><input style={S.input} type="date" value={editing.datum} onChange={e => setEditing({ ...editing, datum: e.target.value })} /></div>
            <div><label style={S.label}>Ort</label><input style={S.input} value={editing.ort} onChange={e => setEditing({ ...editing, ort: e.target.value })} /></div>
          </div>
          <div style={{ marginTop: 12 }}>
            <label style={S.label}>Prüfungskommission</label>
            <input style={S.input} value={editing.prüfer ?? ""} onChange={e => setEditing({ ...editing, prüfer: e.target.value })} placeholder="z.B. Roland Ammermüller" />
          </div>
          <div style={{ marginTop: 16 }}>
            <div style={{ ...S.row, marginBottom: 8 }}>
              <label style={{ ...S.label, margin: 0 }}>Teilnehmer</label>
              <button style={S.btnSm} onClick={addErgebnis} disabled={mitglieder.length === 0}>+ Hinzufügen</button>
            </div>
            {editing.ergebnisse.length === 0 && <p style={{ color: "#8a8680", fontSize: 13 }}>Noch keine Teilnehmer — zuerst Mitglieder unter &laquo;Mitglieder&raquo; erfassen.</p>}
            {editing.ergebnisse.map((e, i) => (
              <div key={i} style={{ ...S.card, padding: 12, marginBottom: 8 }}>
                <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr 1fr auto", gap: 8, alignItems: "end" }}>
                  <div>
                    <label style={S.label}>Mitglied</label>
                    <select style={S.select} value={e.mitgliedId} onChange={ev => {
                      const m = mitglieder.find(m => m.id === ev.target.value);
                      if (!m) return;
                      const u = [...editing.ergebnisse]; u[i] = { ...e, mitgliedId: m.id, mitgliedName: m.name, vorherGrad: m.gürtelgrad };
                      setEditing({ ...editing, ergebnisse: u });
                    }}>
                      {mitglieder.map(m => <option key={m.id} value={m.id}>{m.name}</option>)}
                    </select>
                  </div>
                  <div>
                    <label style={S.label}>Vorher</label>
                    <select style={S.select} value={e.vorherGrad} onChange={ev => { const u=[...editing.ergebnisse]; u[i]={...e,vorherGrad:ev.target.value}; setEditing({...editing,ergebnisse:u}); }}>
                      {GÜRTELGRADE.map(g => <option key={g}>{g}</option>)}
                    </select>
                  </div>
                  <div>
                    <label style={S.label}>Nachher</label>
                    <select style={S.select} value={e.nachherGrad} onChange={ev => { const u=[...editing.ergebnisse]; u[i]={...e,nachherGrad:ev.target.value}; setEditing({...editing,ergebnisse:u}); }}>
                      {GÜRTELGRADE.map(g => <option key={g}>{g}</option>)}
                    </select>
                  </div>
                  <button style={{ ...S.btnDanger, alignSelf: "flex-end", marginBottom: 0 }} onClick={() => { const u=[...editing.ergebnisse]; u.splice(i,1); setEditing({...editing,ergebnisse:u}); }}>×</button>
                </div>
                <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 8 }}>
                  <input type="checkbox" id={`best-${i}`} checked={e.bestanden} onChange={ev => { const u=[...editing.ergebnisse]; u[i]={...e,bestanden:ev.target.checked}; setEditing({...editing,ergebnisse:u}); }} />
                  <label htmlFor={`best-${i}`} style={{ color: "#e8e4df", fontSize: 13 }}>Bestanden (Gürtelgrad wird automatisch aktualisiert)</label>
                </div>
              </div>
            ))}
          </div>
          <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 16 }}>
            <button type="button" style={S.btnGhost} onClick={() => setEditing(null)}>Abbrechen</button>
            <button type="button" style={S.btn} onClick={save}>Speichern</button>
          </div>
        </Modal>
      )}
    </div>
  );
}

// ─── Main ─────────────────────────────────────────────────────────────────────

type Tab = "overview" | "contacts" | "news" | "events" | "training" | "pricing" | "team" | "photos" | "videos" | "holidays" | "dokumente" | "pruefungen" | "security";

const TAB_DEFS: { id: Tab; label: string }[] = [
  { id: "overview", label: "Übersicht" },
  { id: "contacts", label: "Anfragen" },
  { id: "news", label: "News" },
  { id: "events", label: "Termine" },
  { id: "training", label: "Training" },
  { id: "pricing", label: "Preise" },
  { id: "team", label: "Team & Mitglieder" },
  { id: "photos", label: "Fotos" },
  { id: "videos", label: "Lehrfilme" },
  { id: "holidays", label: "Ferien" },
  { id: "dokumente", label: "Dokumente" },
  { id: "pruefungen", label: "Prüfungen" },
  { id: "security", label: "Sicherheit" },
];

export default function AdminPage() {
  const [auth, setAuth] = useState<"loading" | "ok" | "login" | "change-password">("loading");
  const [tab, setTab] = useState<Tab>("overview");
  const [totpEnabled, setTotpEnabled] = useState(false);
  const [weakPassword, setWeakPassword] = useState(false);
  const [isMobile, setIsMobile] = useState(false);
  const { msg, show: toast } = useToast();

  useEffect(() => {
    const check = () => setIsMobile(window.innerWidth < 640);
    check();
    window.addEventListener("resize", check);
    return () => window.removeEventListener("resize", check);
  }, []);

  useEffect(() => {
    apiFetch("/api/admin/check")
      .then(data => { setAuth("ok"); setTotpEnabled(data.totpEnabled ?? false); setWeakPassword(data.weakPassword ?? false); })
      .catch(() => setAuth("login"));
  }, []);

  async function logout() { await fetch("/api/admin/logout", { method: "POST", credentials: "include" }); setAuth("login"); }

  if (auth === "loading") return <div style={{ ...S.page, display: "flex", alignItems: "center", justifyContent: "center" }}><span style={{ color: "#8a8680" }}>Lädt…</span></div>;
  if (auth === "login") return <LoginScreen onLogin={(mustChangePw) => setAuth(mustChangePw ? "change-password" : "ok")} />;
  if (auth === "change-password") return <ForcedPasswordChange onDone={() => setAuth("ok")} />;

  const hasSecurityWarning = weakPassword || !totpEnabled;

  return (
    <div style={S.page}>
      <header style={{ ...S.header, padding: isMobile ? "0 12px" : "0 24px" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={{ fontSize: 20 }}>🥋</span>
          <span style={{ ...S.logo, fontSize: isMobile ? 15 : 18 }}>Dojo Admin</span>
          {!isMobile && <span style={S.badge}>JKA Arbon</span>}
          {!isMobile && hasSecurityWarning && <span style={{ ...S.badgeWarn, marginLeft: 4 }}>⚠ Sicherheit</span>}
          {isMobile && hasSecurityWarning && <span style={{ ...S.badgeWarn, fontSize: 10 }}>⚠</span>}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: isMobile ? 8 : 12 }}>
          {!isMobile && <a href="/" target="_blank" rel="noopener noreferrer" style={{ color: "#8a8680", fontSize: 13, textDecoration: "none" }}>↗ Website</a>}
          <button style={{ ...S.btnLogout, padding: isMobile ? "5px 10px" : "6px 14px", fontSize: isMobile ? 12 : 13 }} onClick={logout}>Abmelden</button>
        </div>
      </header>

      <div style={S.tabs}>
        {TAB_DEFS.map(({ id, label }) => (
          <button key={id} style={S.tab(tab === id)} onClick={() => setTab(id)}>
            {label}{id === "security" && hasSecurityWarning ? " ⚠" : ""}
          </button>
        ))}
      </div>

      <div style={{ ...S.content, padding: isMobile ? "16px 12px" : "24px" }}>
        {tab === "overview" && <Overview onTabChange={setTab} />}
        {tab === "contacts" && <ContactsManager toast={toast} />}
        {tab === "news" && <NewsManager toast={toast} />}
        {tab === "events" && <EventsManager toast={toast} />}
        {tab === "training" && <TrainingManager toast={toast} />}
        {tab === "pricing" && <PricingManager toast={toast} />}
        {tab === "team" && <>
          <TeamManager toast={toast} />
          <div style={{ marginTop: 32 }}><MitgliederManager toast={toast} /></div>
        </>}
        {tab === "photos" && <PhotoManager toast={toast} />}
        {tab === "videos" && <VideoManager toast={toast} />}
        {tab === "holidays" && <HolidaysManager toast={toast} />}
        {tab === "dokumente" && <DokumenteManager toast={toast} />}
        {tab === "pruefungen" && <PruefungenManager toast={toast} />}
        {tab === "security" && <SecurityManager toast={toast} totpEnabled={totpEnabled} weakPassword={weakPassword} onTotpChange={setTotpEnabled} />}
      </div>

      {msg && <div style={S.toast(msg.type)}>{msg.text}</div>}
    </div>
  );
}
