/* AZIS Phase 1 — React Bootstrap (deferred mount) ========================
   Exportiert window.bootReactApp(); bridge.js ruft sie nach Crypto-Unlock.
   Code-Block kommt 1:1 aus archive/pwa-reference/index.html.phase0.bak (vorheriger Stand);
   einzige Aenderungen:
     - ReactDOM.createRoot Target #root → #react-root.
     - render() in window.bootReactApp() gewickelt (nicht auto-fire).
   ====================================================================== */
const { useState, useEffect, useMemo, useCallback, useRef } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "family": "electric",
  "mode": "dark",
  "glow": 1,
  "heroLayout": "split",
  "reduceMotion": false
}/*EDITMODE-END*/;

const TABS = [
  { key: "monat", label: "Monat", icon: "calendar" },
  { key: "einstellungen", label: "Einstellungen", icon: "settings" },
  { key: "export", label: "Export", icon: "download" },
];

function initialTweaks(defaults) {
  const next = { ...defaults };
  let hasStoredFamily = false;
  let hasStoredMode = false;
  try {
    const fam = localStorage.getItem("azis_theme_family_v1") || "";
    const mode = localStorage.getItem("azis_theme_pref_v1") || "";
    if (fam) {
      next.family = fam;
      hasStoredFamily = true;
    }
    if (mode && mode !== "system" && mode !== "camo") {
      next.mode = mode;
      hasStoredMode = true;
    }
    if (mode === "camo" && !fam) {
      next.family = "camo";
      next.mode = "dark";
      hasStoredFamily = true;
      hasStoredMode = true;
    }
  } catch {}
  try {
    const s = typeof AZIS.getSettings === "function" ? AZIS.getSettings() : {};
    if (!hasStoredFamily && s.themeFamily) next.family = s.themeFamily;
    if (!hasStoredMode && s.themeMode) next.mode = s.themeMode;
  } catch {}
  return next;
}

function Root() {
  const initialHash = (typeof location !== "undefined" ? location.hash : "").replace("#", "");
  const initialAdminUnlocked = typeof AZIS.isAdmin === "function" ? AZIS.isAdmin() : false;
  const initialTab = initialHash === "settings" ? "einstellungen"
    : initialHash === "export" ? "export"
    : initialHash === "admin" && initialAdminUnlocked ? "admin"
    : "monat";
  const [t, setTweak] = useTweaks(initialTweaks(TWEAK_DEFAULTS));
  const [tab, setTab] = useState(initialTab);
  const [viewYear, setViewYear] = useState(AZIS.YEAR);
  const [monthIdx, setMonthIdx] = useState(AZIS.MONTH);
  const [days, setDays] = useState(() => AZIS.buildMonth(AZIS.YEAR, AZIS.MONTH));
  const [sheetDay, setSheetDay] = useState(null);
  const [sheetOpen, setSheetOpen] = useState(false);
  const [toast, setToast] = useState(null);
  // Easter-Egg-Theme-Freischaltungen — persistent in localStorage. Eier sind
  // erst SICHTBAR in den Settings nachdem sie freigeschaltet wurden. Trigger:
  //   camo + terminal → 5× Logo tippen
  //   slay-girl       → Nachname "Hrda" in Kopfdaten speichern
  //   ignaz           → Vorname "Daniel" + Nachname "Schmid" in Kopfdaten speichern
  const loadUnlocks = () => {
    const read = (k) => { try { return localStorage.getItem(k) === "1"; } catch { return false; } };
    return {
      camo: read("azis_camo_unlocked_v1"),
      terminal: read("azis_terminal_unlocked_v1"),
      "slay-girl": read("azis_slay_girl_unlocked"),
      "ignaz": read("azis_ignaz_unlocked"),
    };
  };
  const [unlocks, setUnlocks] = useState(loadUnlocks);
  const [tapCount, setTapCount] = useState(0);

  // Hrda-Trigger im SubScreen dispatcht ein Event — hier nehmen wir's auf
  // und aktualisieren die Anzeige + zeigen einen Toast.
  useEffect(() => {
    const onUnlockEvt = (e) => {
      setUnlocks(loadUnlocks());
      const key = e?.detail?.key;
      if (key === "slay-girl") setToast("✨ Slay Girl! freigeschaltet ✨");
      else if (key === "ignaz") setToast("Servus! Ignaz freigeschaltet");
      else if (key === "camo") setToast("Easter Egg: Camo freigeschaltet");
      else if (key === "terminal") setToast("Easter Egg: Terminal freigeschaltet");
    };
    window.addEventListener("azis:theme-unlocked", onUnlockEvt);
    return () => window.removeEventListener("azis:theme-unlocked", onUnlockEvt);
  }, []);
  // Initial: echten Admin-Status aus app.js (gueltiges Token in localStorage)
  // statt Mock. onUnlock/onLogout halten den state weiter synchron.
  const [adminUnlocked, setAdminUnlocked] = useState(initialAdminUnlocked);
  const [intro, setIntro] = useState(initialHash === "intro" ? "full" : null);
  const [subKey, setSubKey] = useState(null);
  const [subOpen, setSubOpen] = useState(false);
  const [holdPct, setHoldPct] = useState(0);
  const holdRef = useRef({});
  const reduced = !!t.reduceMotion;

  const fixed = t.family === "camo" || t.family === "terminal" || t.family === "slay-girl" || t.family === "ignaz";

  // Ignaz-Theme aktiviert den Boarisch-Transformer (bairisch.js). Bei Theme-
  // Wechsel weg von Ignaz: Transformer abschalten + Text-Nodes restaurieren.
  useEffect(() => {
    if (typeof window === "undefined" || !window.AZISBoarisch) return;
    if (t.family === "ignaz") window.AZISBoarisch.activate();
    else window.AZISBoarisch.deactivate();
  }, [t.family]);

  // Welcome-Screen (azis6-welcome.js) zeigt sich einmalig pro localStorage-
  // Marker "azis_seen_welcome_6". Wir feuern den maybeShow-Aufruf KURZ nach
  // Mount damit die Reveal-Animationen nicht direkt mit der Hauptansicht
  // konkurrieren.
  useEffect(() => {
    if (typeof window === "undefined" || !window.AZIS6Welcome) return;
    const id = setTimeout(() => { try { window.AZIS6Welcome.maybeShow(); } catch {} }, 300);
    return () => clearTimeout(id);
  }, []);

  // Hydrate Theme einmalig aus persistierten Quellen: localStorage
  // (azis_theme_family_v1 / azis_theme_pref_v1) hat Prioritaet vor
  // app.js' state.settings — sonst geht der zuletzt gewaehlte Look beim
  // naechsten Boot verloren und faellt auf TWEAK_DEFAULTS=electric/dark.
  const hydratedThemeRef = useRef(true);
  useEffect(() => {
    let famNext, modeNext;
    try { famNext = localStorage.getItem("azis_theme_family_v1") || ""; } catch {}
    try { modeNext = localStorage.getItem("azis_theme_pref_v1") || ""; } catch {}
    if (!famNext || !modeNext) {
      const s = typeof AZIS.getSettings === "function" ? AZIS.getSettings() : {};
      if (!famNext) famNext = s.themeFamily || "";
      if (!modeNext) modeNext = s.themeMode || "";
    }
    const edits = {};
    if (famNext && famNext !== t.family) edits.family = famNext;
    if (modeNext && modeNext !== t.mode) edits.mode = modeNext;
    if (Object.keys(edits).length) setTweak(edits);
  }, []);

  // Persistiere Theme bei jeder Aenderung. Doppelt — localStorage fuer
  // sofortigen Boot, AZIS.saveSettings fuer KV-Sync ueber alle Geraete.
  useEffect(() => {
    if (!hydratedThemeRef.current) return;
    try { localStorage.setItem("azis_theme_family_v1", t.family || "electric"); } catch {}
    try { localStorage.setItem("azis_theme_pref_v1", t.mode || "dark"); } catch {}
    if (typeof AZIS.saveSettings === "function") {
      try { AZIS.saveSettings({ themeFamily: t.family, themeMode: t.mode }); } catch {}
    }
  }, [t.family, t.mode]);

  useEffect(() => {
    const el = document.documentElement;
    el.setAttribute("data-theme-family", t.family || "electric");
    el.setAttribute("data-theme", fixed ? t.family : (t.mode || "dark"));
  }, [t.family, t.mode, fixed]);
  useEffect(() => {
    document.documentElement.style.setProperty("--glow-mult", String(t.glow));
  }, [t.glow]);
  useEffect(() => {
    document.documentElement.classList.toggle("no-motion", reduced);
  }, [reduced]);
  // Synchronisiert die `admin-mode`-Klasse auf <html> mit dem React-Status.
  // Damit ist der duenne rote Top-Streifen (styles.css #1808) wirklich nur
  // sichtbar, wenn der Admin-Bereich auch in der React-UI als aktiv gilt.
  // Wins ueber app.js' applyAdminSettingsUI() bei Race-Conditions auf Boot.
  useEffect(() => {
    document.documentElement.classList.toggle("admin-mode", !!adminUnlocked);
  }, [adminUnlocked]);

  const groups = useMemo(() => AZIS.groupByKW(days), [days]);
  const today = useMemo(() => days.find((d) => d.isToday) || days[0], [days]);

  const openDay = useCallback((day) => {
    setSheetDay(day);
    requestAnimationFrame(() => requestAnimationFrame(() => setSheetOpen(true)));
  }, []);
  const closeDay = useCallback(() => {
    setSheetOpen(false);
    setTimeout(() => setSheetDay(null), 420);
  }, []);

  const saveDay = useCallback((dom, patch) => {
    // Phase 3: persistente Bridge — AZIS.saveDay schreibt in app.js's
    // state.entries + triggert autoSave/KV-Sync. Liefert frische Days.
    // Fallback (Mock-Mode ohne app.js): bleibe beim alten lokalen Patch.
    if (typeof AZIS.saveDay === "function") {
      const fresh = AZIS.saveDay(dom, viewYear, monthIdx, patch);
      if (fresh) {
        setDays(fresh);
        setSheetOpen(false);
        setTimeout(() => setSheetDay(null), 420);
        setToast(pad(dom) + ". " + AZIS.MONTHS[monthIdx] + " gespeichert");
        return;
      }
      return;
    }
    setDays((prev) => prev.map((d) => {
      if (d.dom !== dom) return d;
      const meta = patch.status === "stundenabbau" ? "Ganzer Tag"
        : (patch.b1s ? patch.b1s + "–" + patch.b1e : AZIS.STATUS[patch.status].label);
      return { ...d, status: patch.status, ist: patch.ist, soll: patch.soll, saldo: patch.saldo, b1s: patch.b1s, b1e: patch.b1e, meta, weekend: false };
    }));
    setSheetOpen(false);
    setTimeout(() => setSheetDay(null), 420);
    setToast(pad(dom) + ". " + AZIS.MONTHS[monthIdx] + " gespeichert");
  }, [monthIdx, viewYear]);

  useEffect(() => {
    if (!toast) return;
    const id = setTimeout(() => setToast(null), 2200);
    return () => clearTimeout(id);
  }, [toast]);

  const replayTour = useCallback(() => { setTab("monat"); setIntro("reveal"); }, []);

  const openSub = useCallback((key) => { setSubKey(key); setSubOpen(true); }, []);
  const closeSub = useCallback(() => { setSubOpen(false); setTimeout(() => setSubKey(null), 320); }, []);

  const endHold = useCallback(() => {
    clearTimeout(holdRef.current.timer);
    cancelAnimationFrame(holdRef.current.raf);
    setHoldPct(0);
  }, []);
  const startHold = useCallback(() => {
    if (adminUnlocked) { setTab("admin"); return; }
    holdRef.current.t0 = Date.now();
    const tick = () => {
      const p = Math.min(1, (Date.now() - holdRef.current.t0) / 5000);
      setHoldPct(p);
      if (p < 1) holdRef.current.raf = requestAnimationFrame(tick);
    };
    holdRef.current.raf = requestAnimationFrame(tick);
    holdRef.current.timer = setTimeout(async () => {
      endHold();
      // Phase 5: nach 5s Hold den echten Admin-Login triggern.
      // promptAndLoginAsAdmin oeffnet das vanilla Login-Modal (PW-Eingabe),
      // setzt bei Erfolg den Admin-Token in localStorage und kehrt zurueck.
      try {
        if (typeof AZIS.adminLogin === "function") {
          await AZIS.adminLogin();
        }
      } catch (e) {
        setToast("Admin-Login fehlgeschlagen: " + (e && e.message ? e.message : e));
      }
      if (typeof AZIS.isAdmin === "function" && AZIS.isAdmin()) {
        setAdminUnlocked(true);
        setTab("admin");
        setToast("Admin-Zugang freigeschaltet");
      }
    }, 5000);
  }, [adminUnlocked, endHold]);

  const bumpTap = useCallback(() => {
    if (unlocks.camo && unlocks.terminal) return;
    setTapCount((c) => {
      const n = c + 1;
      if (n >= 5) {
        try {
          localStorage.setItem("azis_camo_unlocked_v1", "1");
          localStorage.setItem("azis_terminal_unlocked_v1", "1");
        } catch {}
        setUnlocks(loadUnlocks());
        setToast("Easter Egg: Camo & Terminal freigeschaltet");
        return 0;
      }
      if (n >= 3) setToast((5 - n) + "× tippen für ein Geheimnis…");
      return n;
    });
  }, [unlocks.camo, unlocks.terminal]);

  const cycleMonth = (dir) => {
    const next = new Date(viewYear, monthIdx + dir, 1);
    const nextYear = next.getFullYear();
    const nextMonth = next.getMonth();
    setViewYear(nextYear);
    setMonthIdx(nextMonth);
    setDays(AZIS.buildMonth(nextYear, nextMonth));
  };

  const { TodayHero, KontoBand, MonthList, SettingsScreen, SubScreen, ExportScreen } = window.AZISApp;
  const AdminDashboard = window.AdminDashboard;
  const AdminLogin = window.AdminLogin;

  const adminLogout = useCallback(() => {
    if (typeof AZIS.adminLogout === "function") AZIS.adminLogout();
    setAdminUnlocked(false);
    setTab("monat");
    setToast("Admin abgemeldet");
  }, []);

  return (
    <div className="app">
      <div className="appbar">
        <div className="brand">
          <button className="brand__mark" onClick={bumpTap} aria-label="AZIS" style={{ cursor: "pointer" }}>
            <AppIcon family={t.family} />
          </button>
          <div>
            <div className="brand__title">AZIS</div>
            <div className="brand__sub">Arbeitszeit-Informationssystem</div>
          </div>
        </div>
        <div className="appbar__pills">
          {adminUnlocked && <span className="admin-pill">Admin</span>}
          <span className={"beta-pill" + (holdPct > 0 ? " holding" : "")} role="button" title="5 Sek. halten für Admin-Zugang"
            onPointerDown={startHold} onPointerUp={endHold} onPointerLeave={endHold} onPointerCancel={endHold}>
            <span className="beta-pill__hold" style={{ width: (holdPct * 100) + "%" }} />6.0
          </span>
        </div>
      </div>

      <div className="scroll" key={tab}>
        {tab === "monat" && (
          <React.Fragment>
            <TodayHero day={today} reduced={reduced} layout={t.heroLayout}
              onPunch={() => setDays(AZIS.buildMonth(viewYear, monthIdx))} />
            <KontoBand days={days} year={viewYear} monthIdx={monthIdx} reduced={reduced}
              onPrev={() => cycleMonth(-1)} onNext={() => cycleMonth(1)} />
            <MonthList groups={groups} onOpen={openDay} reduced={reduced} />
          </React.Fragment>
        )}
        {tab === "einstellungen" && <SettingsScreen
          family={t.family} setFamily={(v) => setTweak("family", v)}
          mode={t.mode} setMode={(v) => setTweak("mode", v)}
          unlocks={unlocks} onOpenSub={openSub} onReplayTour={replayTour} />}
        {tab === "export" && <ExportScreen />}
        {tab === "admin" && adminUnlocked && AdminDashboard && (
          <div className="admin-screen">
            <AdminDashboard onClose={() => setTab("monat")} onLogout={adminLogout} />
          </div>
        )}
        {tab === "admin" && !adminUnlocked && AdminLogin && (
          <div className="admin-screen">
            <AdminLogin
              onAuth={() => { setAdminUnlocked(true); setToast("Admin-Zugang freigeschaltet"); }}
              onCancel={() => setTab("monat")}
            />
          </div>
        )}
      </div>

      <div className="tabbar">
        {TABS.map((tb) => (
          <button key={tb.key} className={"tab" + (tab === tb.key ? " active" : "")} onClick={() => setTab(tb.key)}>
            <Icon name={tb.icon} />
            <span>{tb.label}</span>
          </button>
        ))}
        {adminUnlocked && (
          <button className={"tab tab--admin" + (tab === "admin" ? " active" : "")} onClick={() => setTab("admin")}>
            <Icon name="shield" />
            <span>Admin</span>
          </button>
        )}
      </div>

      <div className={"toast" + (toast ? " show" : "")}>
        <Icon name="check" /><span>{toast}</span>
      </div>

      <SubScreen subKey={subKey} open={subOpen} onClose={closeSub} onSaved={(title) => { closeSub(); setToast(title + " gespeichert"); }} />
      <DaySheet day={sheetDay} open={sheetOpen} onClose={closeDay} onSave={saveDay} reduced={reduced} />

      {intro && <IntroSequence startAt={intro === "reveal" ? "reveal" : "loading"}
        onDone={() => { setIntro(null); try { localStorage.setItem("azis_seen_6", "1"); } catch (e) {} }} />}
    </div>
  );
}

function pad(n) { return String(n).padStart(2, "0"); }

if (typeof window !== "undefined") {
  window.addEventListener("hashchange", () => location.reload());
}

// Phase 1: Bootstrap deferred — bridge.js triggert nach Crypto-Unlock.
window.bootReactApp = function () {
  const mount = document.getElementById("react-root");
  if (!mount) return;
  if (window.__azisReactMounted) return;
  window.__azisReactMounted = true;
  ReactDOM.createRoot(mount).render(<Root />);
};
