// Main app — orchestrates everything
const { useState: uS, useEffect: uE, useRef: uR, useCallback: uCb } = React;

// ===== Scroll reveal hook =====
function useScrollReveal(deps) {
  uE(() => {
    const els = document.querySelectorAll(".reveal:not(.in), .stagger:not(.in)");
    if (!els.length) return;
    // Sections already in viewport on mount: reveal immediately
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          e.target.classList.add("in");
          io.unobserve(e.target);
        }
      });
    }, { threshold: 0.08, rootMargin: "0px 0px -6% 0px" });
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  }, deps || []);
}

// ===== Theme transition (radial sweep + View Transitions API fallback) =====
function animateThemeChange(nextTheme, originX, originY) {
  const root = document.documentElement;
  const targetBg = nextTheme === "dark" ? "#0a0a0c" : "#f3efe7";

  // Add overlay sweep
  const sweep = document.createElement("div");
  sweep.className = "theme-sweep";
  sweep.style.setProperty("--sweep-color", targetBg);
  sweep.style.setProperty("--sweep-x", `${originX}px`);
  sweep.style.setProperty("--sweep-y", `${originY}px`);
  document.body.appendChild(sweep);

  // Swap the theme when the sweep fully covers the screen (~55% of 0.72s).
  setTimeout(() => {
    root.setAttribute("data-theme", nextTheme);
    localStorage.setItem("exb-theme", nextTheme);
  }, 360);
  setTimeout(() => {
    sweep.remove();
  }, 780);
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#ff5b3a",
  "showTicker": true,
  "showScanlines": true,
  "showGrain": true,
  "density": "comfortable",
  "displayFont": "Space Grotesk",
  "showSectionIndex": true,
  "heroLayout": "stacked",
  "filmGrainAmount": 0.05,
  "pageWipe": true,
  "wipeDuration": 900
}/*EDITMODE-END*/;

function App() {
  const [lang, setLangRaw] = uS(() => localStorage.getItem("exb-lang") || "en");
  const [theme, setThemeState] = uS(() => localStorage.getItem("exb-theme") || "dark");
  // Site content (settings, games, team, news) is served from the dev portal's
  // database; fall back to the static bundled data if the API is unreachable
  // (e.g. opened directly as a file://).
  const [siteData, setSiteData] = uS(() => window.EXBYTE_DATA);
  uE(() => {
    Promise.allSettled([
      fetch("/api/settings", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : null)),
      fetch("/api/games", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : null)),
      fetch("/api/team", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : null)),
      fetch("/api/news", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : null)),
    ]).then((results) => {
      const [s, g, t, n] = results.map((x) => (x.status === "fulfilled" ? x.value : null));
      setSiteData((prev) => {
        const d = { ...prev, studio: { ...prev.studio } };
        if (s && s.settings) {
          if (s.settings.studio) d.studio = { ...d.studio, ...s.settings.studio };
          if (s.settings.heroTagline) d.heroTagline = s.settings.heroTagline;
          if (s.settings.heroSub) d.heroSub = s.settings.heroSub;
          if (s.settings.ticker) d.ticker = s.settings.ticker;
        }
        if (g) {
          if (Array.isArray(g.games)) d.games = g.games;
          if (g.featured) d.featured = g.featured;
        }
        if (t && Array.isArray(t.team) && t.team.length) d.team = t.team;
        if (n && Array.isArray(n.news) && n.news.length) d.news = n.news;
        return d;
      });
    });
  }, []);
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const mainRef = uR(null);
  const wipeRef = uR(null);

  // Page wipe transition for nav clicks
  uE(() => {
    const handler = (e) => {
      const a = e.target.closest('a[href^="#"]');
      if (!a) return;
      const href = a.getAttribute("href");
      if (!href || href === "#" || href.length < 2) return;
      const target = document.querySelector(href);
      if (!target) return;
      if (!tweaks.pageWipe) return;
      e.preventDefault();
      const wipe = wipeRef.current;
      if (!wipe) return;
      const dur = tweaks.wipeDuration || 900;
      wipe.style.setProperty("--wipe-duration", `${dur}ms`);
      // Update label to section name
      const labelEl = wipe.querySelector(".page-wipe-label");
      if (labelEl) labelEl.textContent = (a.textContent || "").trim().toUpperCase() || "→";
      wipe.classList.remove("active");
      void wipe.offsetWidth;
      wipe.classList.add("active");
      // Scroll at midpoint when wipe fully covers
      setTimeout(() => {
        target.scrollIntoView({ behavior: "auto", block: "start" });
      }, dur * 0.5);
      setTimeout(() => {
        wipe.classList.remove("active");
      }, dur + 50);
    };
    document.addEventListener("click", handler);
    return () => document.removeEventListener("click", handler);
  }, [tweaks.pageWipe, tweaks.wipeDuration]);

  // Animated theme setter — triggers radial sweep
  const setTheme = uCb((next, evt) => {
    let x = window.innerWidth - 80;
    let y = 60;
    if (evt && evt.currentTarget) {
      const r = evt.currentTarget.getBoundingClientRect();
      x = r.left + r.width / 2;
      y = r.top + r.height / 2;
    }
    animateThemeChange(next, x, y);
    setThemeState(next);
  }, []);

  // Animated language setter — reuses the page-wipe shutter for a slick,
  // consistent transition. The content swaps behind the shutter at its midpoint.
  const setLang = uCb((next) => {
    if (next === lang) return;
    const wipe = wipeRef.current;
    if (!wipe || !tweaks.pageWipe) { setLangRaw(next); return; }
    const dur = Math.min(tweaks.wipeDuration || 900, 760); // snappier for language
    wipe.style.setProperty("--wipe-duration", `${dur}ms`);
    const labelEl = wipe.querySelector(".page-wipe-label");
    if (labelEl) labelEl.textContent = next === "ru" ? "РУССКИЙ" : "ENGLISH";
    wipe.classList.remove("active");
    void wipe.offsetWidth; // restart animation
    wipe.classList.add("active");
    setTimeout(() => setLangRaw(next), dur * 0.5);
    setTimeout(() => wipe.classList.remove("active"), dur + 50);
  }, [lang, tweaks.pageWipe, tweaks.wipeDuration]);

  uE(() => { localStorage.setItem("exb-lang", lang); }, [lang]);
  uE(() => {
    document.documentElement.setAttribute("data-theme", theme);
  }, [theme]);

  useScrollReveal([lang]);

  // apply tweakable CSS variables
  uE(() => {
    const r = document.documentElement;
    r.style.setProperty("--accent", tweaks.accent);
    // recompute rgb from hex
    const hex = tweaks.accent.replace("#", "");
    if (hex.length === 6) {
      const rgb = `${parseInt(hex.slice(0,2),16)}, ${parseInt(hex.slice(2,4),16)}, ${parseInt(hex.slice(4,6),16)}`;
      r.style.setProperty("--accent-rgb", rgb);
    }
    r.style.setProperty("--font-display", `"${tweaks.displayFont}", "Helvetica Neue", Helvetica, Arial, sans-serif`);
    document.body.classList.toggle("no-scanlines", !tweaks.showScanlines);
    document.body.classList.toggle("no-grain", !tweaks.showGrain);
    document.body.classList.toggle("density-compact", tweaks.density === "compact");
    document.body.classList.toggle("density-airy", tweaks.density === "airy");
    document.body.classList.toggle("hide-section-idx", !tweaks.showSectionIndex);
    r.style.setProperty("--grain-opacity", tweaks.filmGrainAmount);
  }, [tweaks]);

  const data = siteData;

  return (
    <>
      {tweaks.showTicker && <Ticker items={data.ticker[lang]} />}
      <Nav lang={lang} setLang={setLang} theme={theme} setTheme={setTheme} />
      <main ref={mainRef} key={lang}>
        <Hero lang={lang} data={data} />
        <FeaturedGame lang={lang} g={data.featured} />
        <Portfolio lang={lang} games={data.games} />
        <NewsFeed lang={lang} news={data.news} />
        <Studio lang={lang} data={data} />
        <Careers lang={lang} jobs={data.jobs} />
        <Press lang={lang} press={data.press} />
        <Submit lang={lang} />
      </main>
      <Footer lang={lang} data={data} />

      <div ref={wipeRef} className="page-wipe" aria-hidden="true">
        <div className="page-wipe-inner">
          <span className="page-wipe-meta">EXBYTE / NAVIGATING</span>
          <span className="page-wipe-label">→</span>
          <div className="page-wipe-bars"><span /><span /><span /></div>
        </div>
      </div>

      <TweaksPanel title="Tweaks" defaultOpen={false}>
        <TweakSection label={lang === "ru" ? "ВНЕШНОСТЬ" : "APPEARANCE"}>
          <TweakColor label="Accent color" value={tweaks.accent} onChange={v => setTweak("accent", v)} />
          <TweakSelect
            label="Display font"
            value={tweaks.displayFont}
            onChange={v => setTweak("displayFont", v)}
            options={[
              { value: "Space Grotesk", label: "Space Grotesk" },
              { value: "Archivo", label: "Archivo" },
              { value: "JetBrains Mono", label: "JetBrains Mono" },
              { value: "Anton", label: "Anton" },
              { value: "Bebas Neue", label: "Bebas Neue" },
            ]}
          />
          <TweakRadio
            label={lang === "ru" ? "Плотность" : "Density"}
            value={tweaks.density}
            onChange={v => setTweak("density", v)}
            options={[
              { value: "compact", label: "Compact" },
              { value: "comfortable", label: "Default" },
              { value: "airy", label: "Airy" },
            ]}
          />
        </TweakSection>
        <TweakSection label={lang === "ru" ? "ЭФФЕКТЫ" : "EFFECTS"}>
          <TweakToggle label={lang === "ru" ? "Бегущая строка" : "Live ticker"} value={tweaks.showTicker} onChange={v => setTweak("showTicker", v)} />
          <TweakToggle label={lang === "ru" ? "VHS-сканлайны" : "VHS scanlines"} value={tweaks.showScanlines} onChange={v => setTweak("showScanlines", v)} />
          <TweakToggle label={lang === "ru" ? "Зерно плёнки" : "Film grain"} value={tweaks.showGrain} onChange={v => setTweak("showGrain", v)} />
          <TweakSlider label={lang === "ru" ? "Сила зерна" : "Grain amount"} value={tweaks.filmGrainAmount} onChange={v => setTweak("filmGrainAmount", v)} min={0} max={0.2} step={0.01} />
          <TweakToggle label={lang === "ru" ? "Индексы секций" : "Section index numbers"} value={tweaks.showSectionIndex} onChange={v => setTweak("showSectionIndex", v)} />
        </TweakSection>
        <TweakSection label={lang === "ru" ? "ПЕРЕХОДЫ" : "TRANSITIONS"}>
          <TweakToggle label={lang === "ru" ? "Шторка при навигации" : "Page wipe on nav"} value={tweaks.pageWipe} onChange={v => setTweak("pageWipe", v)} />
          <TweakSlider label={lang === "ru" ? "Длительность шторки (мс)" : "Wipe duration (ms)"} value={tweaks.wipeDuration} onChange={v => setTweak("wipeDuration", v)} min={400} max={2000} step={50} />
        </TweakSection>
      </TweaksPanel>
    </>
  );
}

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