/* ============================================================
   APP — composition, language, tweaks, theme, scroll reveals
   ============================================================ */
const { useState: aUS, useEffect: aUE } = React;

const FONT_MAP = {
  Archivo: { stack: '"Archivo", system-ui, sans-serif', wght: 840 },
  Anton:   { stack: '"Anton", system-ui, sans-serif', wght: 400 },
  Syne:    { stack: '"Syne", system-ui, sans-serif', wght: 800 },
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "cursor": "dot",
  "displayFont": "Archivo",
  "theme": "dark",
  "grain": true,
  "name": "Alexandre Halter"
}/*EDITMODE-END*/;

const LANG_KEY = "ah_portfolio_lang";

function useScrollReveal(dep) {
  aUE(() => {
    const els = document.querySelectorAll(".reveal");
    const io = new IntersectionObserver((ents) => {
      ents.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } });
    }, { threshold: 0.05, rootMargin: "0px 0px -8% 0px" });
    els.forEach((el) => io.observe(el));
    // safety net: never let content stay hidden (e.g. throttled transitions)
    const safety = setTimeout(() => els.forEach((el) => el.classList.add("in")), 1800);
    return () => { io.disconnect(); clearTimeout(safety); };
  }, [dep]);
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [lang, setLang] = aUS(() => {
    try { return localStorage.getItem(LANG_KEY) || "fr"; } catch (e) { return "fr"; }
  });
  const [open, setOpen] = aUS(null);

  aUE(() => { try { localStorage.setItem(LANG_KEY, lang); } catch (e) {} document.documentElement.lang = lang; }, [lang]);
  aUE(() => { document.documentElement.dataset.theme = t.theme; }, [t.theme]);
  aUE(() => {
    const f = FONT_MAP[t.displayFont] || FONT_MAP.Archivo;
    document.documentElement.style.setProperty("--display", f.stack);
    document.documentElement.style.setProperty("--display-wght", f.wght);
  }, [t.displayFont]);
  aUE(() => { const g = document.querySelector(".grain"); if (g) g.classList.toggle("on", !!t.grain); }, [t.grain]);

  useScrollReveal(lang);

  const L = window.I18N[lang];

  return (
    <React.Fragment>
      <Cursor style={t.cursor} />
      <ScrollProgress />

      <nav className="topbar">
        <div className="topbar-right">
          <nav>
            <a href="#work" data-cursor="→">{L.navWork}</a>
            <a href="#cv" data-cursor="→">{L.navCV}</a>
            <a href="#about" data-cursor="→">{L.navAbout}</a>
            <a href="#contact" data-cursor="→">{L.navContact}</a>
          </nav>
          <LangSwitch lang={lang} onChange={setLang} />
        </div>
      </nav>

      <main>
        <Hero name={t.name} lang={lang} />
        <Work lang={lang} onOpen={setOpen} />
        <CV lang={lang} />
        <About lang={lang} />
        <Distance lang={lang} />
        <Footprint lang={lang} />
        <Contact lang={lang} email="alex57reton@gmail.com" linkedin="https://www.linkedin.com/in/alexandre-h-8910a3108/" />
      </main>

      {open && <Lightbox project={open} lang={lang} onClose={() => setOpen(null)} />}

      <TweaksPanel>
        <TweakSection label="Cursor" />
        <TweakRadio label="Style" value={t.cursor} options={["dot", "ring", "off"]}
          onChange={(v) => setTweak("cursor", v)} />

        <TweakSection label="Type & theme" />
        <TweakSelect label="Display font" value={t.displayFont}
          options={["Archivo", "Anton", "Syne"]}
          onChange={(v) => setTweak("displayFont", v)} />
        <TweakRadio label="Theme" value={t.theme} options={["dark", "light"]}
          onChange={(v) => setTweak("theme", v)} />
        <TweakToggle label="Film grain" value={t.grain}
          onChange={(v) => setTweak("grain", v)} />

        <TweakSection label="Identity" />
        <TweakText label="Name" value={t.name} onChange={(v) => setTweak("name", v)} />
      </TweaksPanel>
    </React.Fragment>
  );
}

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