// app.jsx — composes the page, wires tweaks, reveals, konami + console easter eggs
const { useEffect: useEffectApp, useState: useStateApp } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "heroVariant": "centered",
  "accent": "balanced",
  "codeTexture": true,
  "scrollGrading": true,
  "calm": false
}/*EDITMODE-END*/;

// 11x8 Space Invader bitmap — used only for the konami rain
const INV = ["00100000100","00010001000","00111111100","01101110110","11111111111","10111111101","10100000101","00011011000"];
function invShadow(px) {
  const out = [];
  INV.forEach((row, y) => [...row].forEach((c, x) => { if (c === "1") out.push(`${x*px}px ${y*px}px currentColor`); }));
  return out.join(",");
}

const ACCENTS = {
  balanced: { grad: "linear-gradient(120deg, #C2477F 0%, #6D4FD0 100%)", focal: "radial-gradient(120% 140% at 18% 0%, #C2477F 0%, #8341C9 42%, #5B3FBF 100%)", focalH: "radial-gradient(120% 140% at 18% 0%, #D2528C 0%, #8E49D6 42%, #6446CE 100%)", glow: "#9B7BE0" },
  violet:   { grad: "linear-gradient(120deg, #8A66E6 0%, #5B3FBF 100%)", focal: "radial-gradient(120% 140% at 18% 0%, #8A66E6 0%, #6D4FD0 45%, #4E33B0 100%)", focalH: "radial-gradient(120% 140% at 18% 0%, #9A78F0 0%, #7C5CE0 45%, #5B3FBF 100%)", glow: "#A98BEA" },
  rose:     { grad: "linear-gradient(120deg, #D2528C 0%, #B23A78 100%)", focal: "radial-gradient(120% 140% at 18% 0%, #D2528C 0%, #B23A78 48%, #7E2F7A 100%)", focalH: "radial-gradient(120% 140% at 18% 0%, #E060A0 0%, #C2477F 48%, #8E3A86 100%)", glow: "#E58FBC" },
};

function KonamiToast({ quote }) {
  return (
    <React.Fragment>
      <div className="konami-back show"></div>
      <div className="konami-toast show" role="status">
        <div className="seq">▲ ▲ ▼ ▼ ◄ ► ◄ ► B A</div>
        <div className="ktitle">cheat unlocked</div>
        <div className="sub">god mode · <b>+30 lives</b> · invasion launched<br />{quote}</div>
      </div>
    </React.Fragment>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [konami, setKonami] = useStateApp(null);

  // apply visual tweaks to the document
  useEffectApp(() => {
    const root = document.documentElement;
    root.setAttribute("data-codetex", t.codeTexture ? "on" : "off");
    root.setAttribute("data-calm", t.calm ? "on" : "off");
    root.setAttribute("data-grade", t.scrollGrading ? "on" : "off");
    const a = ACCENTS[t.accent] || ACCENTS.balanced;
    root.style.setProperty("--accent-gradient", a.grad);
    root.style.setProperty("--fill-focal", a.focal);
    root.style.setProperty("--fill-focal-hover", a.focalH);
    root.style.setProperty("--accent-glow", a.glow);
  }, [t.codeTexture, t.calm, t.scrollGrading, t.accent]);

  // scroll-driven background grading — getBoundingClientRect band test (scroller-agnostic, no IO dependency)
  useEffectApp(() => {
    const root = document.documentElement;
    if (!t.scrollGrading) { root.setAttribute("data-theme", "hero"); return; }
    const ids = ["top", "about", "focus", "projects", "articles", "status", "contact"];
    const themeFor = (id) => (id === "top" ? "hero" : id);
    const pick = () => {
      const band = (window.innerHeight || 800) * 0.4;   // the "active" scan line
      let best = "top";
      for (const id of ids) {
        const el = document.getElementById(id);
        if (!el) continue;
        const r = el.getBoundingClientRect();
        if (r.top <= band && r.bottom > band) { best = id; }   // last section crossing the line wins
      }
      const next = themeFor(best);
      if (root.getAttribute("data-theme") !== next) root.setAttribute("data-theme", next);
    };
    pick();
    let ticking = false;
    const onScroll = () => { if (ticking) return; ticking = true; requestAnimationFrame(() => { ticking = false; pick(); }); };
    window.addEventListener("scroll", onScroll, { passive: true });
    document.addEventListener("scroll", onScroll, { passive: true, capture: true });
    window.addEventListener("resize", onScroll);
    const settle = setTimeout(pick, 200);   // re-pick after layout settles
    return () => { window.removeEventListener("scroll", onScroll); document.removeEventListener("scroll", onScroll, { capture: true }); window.removeEventListener("resize", onScroll); clearTimeout(settle); };
  }, [t.scrollGrading, t.heroVariant]);

  // code-texture parallax: drift the code layer with scroll (gated by codeTexture + motion prefs)
  useEffectApp(() => {
    const code = document.querySelector(".codetex");
    if (!code) return;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (!t.codeTexture || t.calm || reduce) { code.style.setProperty("--code-scroll", "0px"); return; }
    let ticking = false;
    const update = () => {
      ticking = false;
      const h = document.documentElement;
      const max = h.scrollHeight - h.clientHeight;
      const p = max > 0 ? Math.min(1, Math.max(0, h.scrollTop / max)) : 0;
      const range = window.innerHeight * 0.42;        // total parallax travel
      code.style.setProperty("--code-scroll", (-p * range).toFixed(1) + "px");
    };
    const onScroll = () => { if (ticking) return; ticking = true; requestAnimationFrame(update); };
    update();
    window.addEventListener("scroll", onScroll, { passive: true });
    document.addEventListener("scroll", onScroll, { passive: true, capture: true });
    window.addEventListener("resize", onScroll);
    return () => { window.removeEventListener("scroll", onScroll); document.removeEventListener("scroll", onScroll, { capture: true }); window.removeEventListener("resize", onScroll); };
  }, [t.codeTexture, t.calm]);

  // render lucide icons + refresh on DOM changes (variant switches add icons)
  useEffectApp(() => {
    const render = () => window.lucide && window.lucide.createIcons();
    render();
    let raf = 0;
    const refresh = () => { if (raf) return; raf = requestAnimationFrame(() => { raf = 0; if (document.querySelector("i[data-lucide]")) render(); }); };
    const mo = new MutationObserver(refresh);
    mo.observe(document.body, { childList: true, subtree: true });
    return () => mo.disconnect();
  });

  // scroll reveals
  useEffectApp(() => {
    const io = new IntersectionObserver(
      (entries) => entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } }),
      { threshold: 0.1, rootMargin: "0px 0px -8% 0px" }
    );
    document.querySelectorAll(".reveal:not(.in)").forEach((el) => io.observe(el));
    return () => io.disconnect();
  }, [t.heroVariant]);

  // console nod + konami code
  useEffectApp(() => {
    const css = "color:#9B7BE0;font-family:monospace;font-size:12px";
    console.log("%c» sirucka.cz — building order from chaos.\n» psst… try the Konami code: ↑↑↓↓←→←→ B A\n» may the tests be with you. 42.", css);

    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const SEQ = ["ArrowUp","ArrowUp","ArrowDown","ArrowDown","ArrowLeft","ArrowRight","ArrowLeft","ArrowRight","b","a"];
    const QUOTES = [
      "\u201cGet to the choppa!\u201d — deploy started.",
      "\u201cStay frosty.\u201d — production is calm.",
      "\u201cThere is no spoon.\u201d — only tests.",
      "\u201cResistance is futile.\u201d — code review approved.",
    ];
    let pos = 0;
    function rain() {
      const colors = ["#9B7BE0", "#C2477F", "#6D4FD0", "#4ADE9E"];
      const frag = document.createDocumentFragment();
      const nodes = [];
      for (let i = 0; i < 18; i++) {
        const d = document.createElement("div");
        d.className = "falling-invader";
        const px = 2 + Math.random() * 2.2;
        d.style.color = colors[i % colors.length];
        d.style.left = Math.random() * 100 + "vw";
        d.style.boxShadow = invShadow(px);
        d.style.width = d.style.height = px + "px";
        const dur = 2.6 + Math.random() * 2.6;
        d.style.animation = `fall ${dur}s linear ${Math.random() * 1.1}s forwards`;
        frag.appendChild(d); nodes.push([d, (dur + 1.4) * 1000]);
      }
      document.body.appendChild(frag);
      nodes.forEach(([d, ms]) => setTimeout(() => d.remove(), ms));
    }
    function onKey(e) {
      const k = e.key.length === 1 ? e.key.toLowerCase() : e.key;
      pos = (k === SEQ[pos]) ? pos + 1 : (k === SEQ[0] ? 1 : 0);
      if (pos === SEQ.length) {
        pos = 0;
        setKonami(QUOTES[Math.floor(Math.random() * QUOTES.length)]);
        if (!reduce) rain();
        setTimeout(() => setKonami(null), 4200);
      }
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  const onGo = (e, id) => {
    e.preventDefault();
    const el = document.getElementById(id);
    if (el) {
      const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
      window.scrollTo({ top: el.getBoundingClientRect().top + window.scrollY - 72, behavior: reduce ? "auto" : "smooth" });
    }
  };

  return (
    <React.Fragment>
      <Atmosphere />
      <ScrollProgress />
      <div className="page">
        <Nav />
        <Hero variant={t.heroVariant} onGo={onGo} />
        <About />
        <Focus />
        <Projects />
        <Articles />
        <StatusLog />
        <Contact />
        <Footer />
      </div>
      {konami && <KonamiToast quote={konami} />}

      <TweaksPanel>
        <TweakSection label="Hero" />
        <TweakRadio label="Layout" value={t.heroVariant}
          options={["centered", "split", "terminal"]}
          onChange={(v) => setTweak("heroVariant", v)} />
        <TweakSection label="Atmosphere" />
        <TweakRadio label="Accent" value={t.accent}
          options={["balanced", "violet", "rose"]}
          onChange={(v) => setTweak("accent", v)} />
        <TweakToggle label="Code texture" value={t.codeTexture}
          onChange={(v) => setTweak("codeTexture", v)} />
        <TweakToggle label="Scroll color grading" value={t.scrollGrading}
          onChange={(v) => setTweak("scrollGrading", v)} />
        <TweakToggle label="Calm mode (less motion)" value={t.calm}
          onChange={(v) => setTweak("calm", v)} />
      </TweaksPanel>
    </React.Fragment>
  );
}

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