/* global React, ReactDOM, SECTIONS, MNEMONICS, Topbar, Sidebar, Card, AuthModal, EditSheet, btnStyle, btnClass, I */
const { useState, useMemo, useEffect } = React;

const blank = () => ({
  id: "m-" + Math.random().toString(36).slice(2,8),
  section: SECTIONS[0].id,
  category: SECTIONS[0].categories[0].id,
  title: "",
  mnemonic: "",
  expansion: [["",""]],
  note: "",
  tags: [],
  author: "Anonym"
});

// ── Relative-Zeit-Formatierung für updated_at ─────────────────────
const fmtRelative = (iso) => {
  if (!iso) return "—";
  const t = new Date(iso).getTime();
  if (isNaN(t)) return iso;
  const diff = (Date.now() - t) / 1000;
  if (diff < 60) return "gerade eben";
  if (diff < 3600) return `vor ${Math.floor(diff/60)} Min`;
  if (diff < 86400) return `vor ${Math.floor(diff/3600)} Std`;
  if (diff < 86400*7) return `vor ${Math.floor(diff/86400)} Tagen`;
  if (diff < 86400*30) return `vor ${Math.floor(diff/(86400*7))} Wochen`;
  if (diff < 86400*365) return `vor ${Math.floor(diff/(86400*30))} Monaten`;
  return `vor ${Math.floor(diff/(86400*365))} Jahren`;
};
window.fmtRelative = fmtRelative;

// ── API ───────────────────────────────────────────────────────────
const API = {
  async list() {
    const r = await fetch("/api/eselsbruecken");
    if (!r.ok) throw new Error("list_failed");
    return r.json();
  },
  async create(item, code) {
    const r = await fetch("/api/eselsbruecken", {
      method: "POST",
      headers: { "Content-Type": "application/json", "X-Access-Code": code },
      body: JSON.stringify(item),
    });
    if (!r.ok) throw new Error("create_failed");
    return r.json();
  },
  async update(item, code) {
    const r = await fetch(`/api/eselsbruecken?id=${encodeURIComponent(item.id)}`, {
      method: "PUT",
      headers: { "Content-Type": "application/json", "X-Access-Code": code },
      body: JSON.stringify(item),
    });
    if (!r.ok) throw new Error("update_failed");
    return r.json();
  },
  async remove(id, code) {
    const r = await fetch(`/api/eselsbruecken?id=${encodeURIComponent(id)}`, {
      method: "DELETE",
      headers: { "X-Access-Code": code },
    });
    if (!r.ok && r.status !== 204) throw new Error("delete_failed");
  },
  async verify(code) {
    const r = await fetch("/api/auth", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ code }),
    });
    return r.ok;
  },
};

// Ein Kenncode fürs ganze Portal: beim Site-Login (Root-Gate) wird er als
// "mg_code" gemerkt. Eselsbrücken nutzt ihn direkt – kein zweiter Dialog.
const readSiteCode = () => { try { return localStorage.getItem("mg_code") || ""; } catch (e) { return ""; } };

function App() {
  const [accessCode, setAccessCode] = useState(readSiteCode);
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(true);
  const [loadError, setLoadError] = useState(null);
  const [active, setActive] = useState({ section: "_all", category: null });
  const [query, setQuery] = useState("");
  const [editing, setEditing] = useState(null);
  const [saving, setSaving] = useState(false);
  const [mobileNavOpen, setMobileNavOpen] = useState(false);

  const unlocked = !!accessCode;

  // Auth ist portal-weit: fehlt der Kenncode, zum einen Site-Gate leiten;
  // Abmelden räumt die portal-weite Freischaltung ab.
  const goToGate = () => { window.location.href = "/?next=" + encodeURIComponent("/eselsbruecken"); };
  const siteLogout = () => {
    try { localStorage.removeItem("mg_admin"); localStorage.removeItem("mg_code"); } catch (e) {}
    document.cookie = "mg_admin=; Max-Age=0; Path=/; SameSite=Lax";
    window.location.href = "/";
  };

  useEffect(() => {
    document.body.style.overflow = mobileNavOpen ? "hidden" : "";
    return () => { document.body.style.overflow = ""; };
  }, [mobileNavOpen]);

  // Initial load from API; fall back to seeds if the API is unavailable
  useEffect(() => {
    let cancelled = false;
    setLoading(true);
    API.list()
      .then(rows => { if (!cancelled) { setItems(rows); setLoadError(null); } })
      .catch(err => {
        console.error("Load failed, using seed data:", err);
        if (!cancelled) { setItems(MNEMONICS); setLoadError("offline"); }
      })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, []);

  const sectionMap = useMemo(()=>({
    sections: Object.fromEntries(SECTIONS.map(s => [s.id, s]))
  }), []);

  const counts = useMemo(()=>{
    const section = {}, category = {};
    items.forEach(it=>{
      section[it.section] = (section[it.section]||0)+1;
      category[it.section+":"+it.category] = (category[it.section+":"+it.category]||0)+1;
    });
    return { section, category };
  }, [items]);

  const filtered = useMemo(()=>{
    const q = query.trim().toLowerCase();
    return items.filter(it => {
      if (active.section !== "_all" && it.section !== active.section) return false;
      if (active.category && it.category !== active.category) return false;
      if (!q) return true;
      const hay = [it.title, it.mnemonic, it.note, ...(it.tags||[]), ...(it.expansion||[]).flat()].join(" ").toLowerCase();
      return hay.includes(q);
    });
  }, [items, active, query]);

  const activeTitle = useMemo(()=>{
    if (active.section === "_all") return {
      kicker:"Alle Sektionen",
      title:"Alle Eselsbrücken",
      blurb:"Querschnitt aller bisher gesammelten Merksätze — von Anatomie bis Notfallmedizin.",
      gradient: true,
    };
    const sec = sectionMap.sections[active.section];
    if (!sec) return null;
    if (active.category) {
      const cat = sec.categories.find(c => c.id === active.category);
      return { kicker: `${sec.group || "Sektion"} · ${sec.title}`, title: cat ? cat.title : "—", blurb: sec.blurb };
    }
    return { kicker: sec.group || "Sektion", title: sec.title, blurb: sec.blurb };
  }, [active, sectionMap]);

  const onSave = async () => {
    if (!editing || !accessCode) return;
    setSaving(true);
    try {
      const item = editing.item;
      // Strip empty expansion rows
      const cleaned = {
        ...item,
        expansion: (item.expansion || []).filter(([k,v]) => (k||"").trim() || (v||"").trim()),
        author: (item.author || "").trim() || "Anonym",
      };
      const saved = editing.isNew
        ? await API.create(cleaned, accessCode)
        : await API.update(cleaned, accessCode);
      setItems(prev => {
        const exists = prev.some(p => p.id === saved.id);
        return exists ? prev.map(p => p.id === saved.id ? saved : p) : [saved, ...prev];
      });
      setEditing(null);
    } catch (e) {
      alert("Speichern fehlgeschlagen. Bitte erneut versuchen oder Kenncode prüfen.");
      console.error(e);
    } finally {
      setSaving(false);
    }
  };

  const onDelete = async (id) => {
    if (!accessCode) return;
    if (!confirm("Diese Eselsbrücke wirklich löschen?")) return;
    try {
      await API.remove(id, accessCode);
      setItems(prev => prev.filter(p => p.id !== id));
    } catch (e) {
      alert("Löschen fehlgeschlagen.");
      console.error(e);
    }
  };

  const onEdit = (id) => {
    const it = items.find(p => p.id === id);
    if (it) setEditing({
      item: { ...it, expansion: it.expansion ? it.expansion.map(r=>[...r]) : [["",""]] },
      isNew: false,
    });
  };

  const onAdd = () => {
    const init = blank();
    if (active.section !== "_all") init.section = active.section;
    if (active.category) init.category = active.category;
    setEditing({ item: init, isNew: true });
  };

  // Cmd/Ctrl+K → Suche fokussieren
  useEffect(()=>{
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        const el = document.querySelector('input[placeholder^="Suche"]');
        el && el.focus();
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  return (
    <div className="app">
      <Topbar
        query={query} setQuery={setQuery}
        unlocked={unlocked}
        onLockClick={goToGate}
        onLogout={siteLogout}
        onMenuToggle={()=>setMobileNavOpen(o => !o)}
        mobileNavOpen={mobileNavOpen}
      />

      <Sidebar
        sections={SECTIONS}
        active={active}
        setActive={setActive}
        counts={counts}
        total={items.length}
        unlocked={unlocked}
        mobileOpen={mobileNavOpen}
        onClose={()=>setMobileNavOpen(false)}
      />

      <main className="main-content" style={mainStyles.main}>
        <div className="main-header" style={mainStyles.header}>
          <div style={{minWidth:0}}>
            <div style={mainStyles.kicker}>{activeTitle.kicker}</div>
            <h1
              className={"main-title " + (activeTitle.gradient ? "gradient-text" : "")}
              style={mainStyles.title}
            >
              {activeTitle.title}
            </h1>
            <p className="main-blurb" style={mainStyles.blurb}>{activeTitle.blurb}</p>
          </div>
          <div style={{display:"flex", gap:12, alignItems:"center", flexWrap:"wrap"}}>
            <div style={mainStyles.resultCount}>
              <span className="mono" style={{color:"var(--ink)", fontWeight:600}}>{filtered.length}</span>
              <span style={{color:"var(--ink-3)"}}>von {items.length}</span>
            </div>
            {unlocked && (
              <button className={btnClass.primary} onClick={onAdd} style={btnStyle.primary}>
                <I.Plus size={15}/> Neue Eselsbrücke
              </button>
            )}
          </div>
        </div>

        {loadError && (
          <div style={{
            padding:"12px 16px", borderRadius:12,
            background:"rgba(229,72,77,0.08)", border:"1px solid rgba(229,72,77,0.20)",
            color:"#9a2d31", fontSize:13.5, marginBottom:18,
            display:"flex", alignItems:"center", gap:10,
          }}>
            <span>⚠</span>
            <span>Server nicht erreichbar — zeige Beispiel-Daten. Neue Eselsbrücken werden nicht gespeichert.</span>
          </div>
        )}

        {loading ? (
          <div style={{textAlign:"center", padding:"80px 20px", color:"var(--ink-3)"}}>
            Lade Eselsbrücken…
          </div>
        ) : filtered.length === 0 ? (
          <EmptyState query={query} unlocked={unlocked} onAdd={onAdd}/>
        ) : (
          <div className="cards-grid" style={mainStyles.grid}>
            {filtered.map((item, i) => (
              <div
                key={item.id}
                className="card-mount"
                style={{ animationDelay: `${Math.min(i, 8) * 35}ms` }}
              >
                <Card
                  item={item}
                  sectionMap={sectionMap}
                  onEdit={onEdit}
                  onDelete={onDelete}
                  unlocked={unlocked}
                />
              </div>
            ))}
          </div>
        )}

        <div className="main-footer" style={mainStyles.footer}>
          <div style={{display:"flex", alignItems:"center", gap:8, fontSize:13}}>
            <span style={{fontWeight:800, fontSize:15}}>
              <span style={{color:"var(--med-green)"}}>Med</span><span style={{color:"var(--gang-blue)"}}>Gang</span>
            </span>
            <span style={{color:"var(--ink-3)"}}>· Eselsbrücken · kein Ersatz für Lehrbücher</span>
          </div>
          <div className="mono" style={{fontSize:11, color:"var(--ink-3)"}}>v0.1 · prototype</div>
        </div>
      </main>

      <EditSheet
        open={!!editing}
        onClose={()=>!saving && setEditing(null)}
        value={editing ? editing.item : null}
        onChange={(v)=>setEditing({ ...editing, item: v })}
        onSave={onSave}
        onCancel={()=>!saving && setEditing(null)}
        sections={SECTIONS}
        isNew={editing ? editing.isNew : false}
        saving={saving}
      />
    </div>
  );
}

const EmptyState = ({ query, unlocked, onAdd }) => (
  <div style={{
    border:"1px dashed var(--line-2)", borderRadius:"var(--radius-lg)",
    padding:"64px 32px", textAlign:"center", background:"#fff",
    display:"flex", flexDirection:"column", alignItems:"center", gap:16,
  }}>
    <div style={{
      width:52, height:52, borderRadius:14,
      background:"linear-gradient(135deg, rgba(31,194,138,0.10), rgba(74,140,255,0.10))",
      display:"grid", placeItems:"center", color:"var(--gang-blue)",
    }}>
      <I.Search size={22}/>
    </div>
    <div>
      <div style={{fontSize:22, fontWeight:800, letterSpacing:"-0.02em"}}>
        Nichts gefunden{query ? <> zu „{query}"</> : ""}.
      </div>
      <div style={{color:"var(--ink-3)", marginTop:8, maxWidth:440, fontSize:14, lineHeight:1.5}}>
        Versuch eine andere Sektion oder einen anderen Suchbegriff. Du kannst Sprüche auch direkt
        nach Stichwort, Tag oder Anatomie-Begriff durchsuchen.
      </div>
    </div>
    {unlocked && (
      <button className={btnClass.primary} onClick={onAdd} style={btnStyle.primary}>
        <I.Plus size={15}/> Eselsbrücke anlegen
      </button>
    )}
  </div>
);

const mainStyles = {
  main: { padding:"36px 40px 80px", maxWidth:1280, width:"100%", margin:"0 auto" },
  header: {
    display:"flex", justifyContent:"space-between", alignItems:"flex-end",
    gap:24, marginBottom:32, flexWrap:"wrap",
  },
  kicker: {
    fontSize:11, textTransform:"uppercase", letterSpacing:"0.16em",
    color:"var(--ink-3)", marginBottom:8, fontWeight:700,
  },
  title: {
    margin:0, fontSize:48, lineHeight:1.05, letterSpacing:"-0.03em",
    fontWeight:800,
  },
  blurb: { margin:"10px 0 0", color:"var(--ink-2)", fontSize:15, maxWidth:580, lineHeight:1.55 },
  resultCount: {
    display:"inline-flex", alignItems:"baseline", gap:6,
    padding:"8px 14px",
    border:"1px solid var(--line)", borderRadius:999, background:"#fff",
    fontSize:12, fontFamily:"Geist Mono",
  },
  grid: {
    display:"grid",
    gridTemplateColumns:"repeat(auto-fill, minmax(360px, 1fr))",
    gap:20,
  },
  footer: {
    marginTop:60, paddingTop:24, borderTop:"1px solid var(--line)",
    display:"flex", justifyContent:"space-between", alignItems:"center",
    fontSize:13, color:"var(--ink-2)", flexWrap:"wrap", gap:10,
  },
};

ReactDOM.createRoot(document.getElementById("root")).render(<App/>);
