/* ============================================================
   SE42 · Landing — app root (arquitectura Novu reinterpretada)
   ============================================================ */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#E6E779",
  "serif": "normal",
  "heroVeil": 0.46,
  "footerVeil": 0.62
}/*EDITMODE-END*/;

const LANG_KEY = "se42_landing_lang";

function App() {
  const [tw, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [lang, setLangState] = useState(() => {
    try {
      const saved = localStorage.getItem(LANG_KEY);
      if (saved === "es" || saved === "en") return saved;
      return (navigator.language || "es").toLowerCase().startsWith("en") ? "en" : "es";
    } catch (e) { return "es"; }
  });
  const [scrolled, setScrolled] = useState(false);
  const [menuOpen, setMenuOpen] = useState(false);
  const [active, setActive] = useState(0);

  /* intro de carga — solo la primera vez por sesión, sincronizada con la
     disponibilidad real del hero (póster + fuentes) para que nunca arranque en blanco */
  useEffect(() => {
    const root = document.documentElement;
    if (!root.classList.contains("intro-play")) return;
    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    window.scrollTo(0, 0);

    let finished = false;
    const finish = () => {
      if (finished) return; finished = true;
      root.classList.remove("intro-play", "intro-reveal");
      root.classList.add("intro-done");
      document.body.style.overflow = prevOverflow;
      try { sessionStorage.setItem("se42_intro_seen", "1"); } catch (e) {}
    };

    let started = false, finishTmr = 0;
    const startReveal = () => {
      if (started) return; started = true;
      root.classList.add("intro-reveal");      // dispara la línea de tiempo CSS
      finishTmr = setTimeout(finish, 2700);     // al terminar el titular
    };

    // Espera a que el póster del hero esté decodificado y las fuentes listas
    const poster = (data.assets.heroBg) || "";
    const imgReady = new Promise((res) => {
      if (!poster) return res();
      const im = new Image();
      im.onload = res; im.onerror = res; im.src = poster;
      if (im.complete) res();
    });
    const fontsReady = (document.fonts && document.fonts.ready) ? document.fonts.ready : Promise.resolve();
    const ready = Promise.all([imgReady, fontsReady]);
    const cap = new Promise((res) => setTimeout(res, 1100));   // tope: nunca esperar de más
    Promise.race([ready, cap]).then(startReveal);

    const hardCap = setTimeout(finish, 4200);
    return () => { clearTimeout(finishTmr); clearTimeout(hardCap); document.body.style.overflow = prevOverflow; };
  }, []);

  const stepEls = useRef([]);
  const footerRef = useRef(null);

  const setLang = (l) => {
    setLangState(l);
    try { localStorage.setItem(LANG_KEY, l); } catch (e) {}
  };
  const registerStep = (i, el) => { stepEls.current[i] = el; };

  const data = window.SE42_LANDING;
  const t = data[lang];
  const screens = data.screens;
  const install = useInstall(data.install.appUrl);

  /* tweaks → CSS vars */
  useEffect(() => {
    const r = document.documentElement;
    r.style.setProperty("--accent", tw.accent);
    r.style.setProperty("--serif-style", tw.serif);
    r.style.setProperty("--hero-veil", String(tw.heroVeil));
    r.style.setProperty("--footer-veil", String(tw.footerVeil));
    r.lang = lang;
  }, [tw, lang]);

  /* SEO: título, descripción e idioma del documento + datos estructurados por idioma */
  useEffect(() => {
    const seo = {
      es: {
        title: "Guía SE42 · Santa Engracia 42",
        desc: "SE42 reúne incidencias, reservas, paquetes, portería y avisos de Santa Engracia 42 en una sola app web — desde tu pantalla de inicio, sin App Store.",
      },
      en: {
        title: "SE42 Guide · Santa Engracia 42",
        desc: "SE42 brings issues, bookings, packages, the concierge and notices of Santa Engracia 42 into one web app — from your Home Screen, no App Store.",
      },
    }[lang] || {};
    if (seo.title) document.title = seo.title;
    const md = document.querySelector('meta[name="description"]');
    if (md && seo.desc) md.setAttribute("content", seo.desc);
    document.documentElement.setAttribute("lang", lang);

    // FAQPage + WebApplication a partir del contenido actual
    const faqItems = (t.faq && t.faq.items) || [];
    const ld = {
      "@context": "https://schema.org",
      "@graph": [
        {
          "@type": "WebApplication",
          "name": "SE42",
          "applicationCategory": "LifestyleApplication",
          "operatingSystem": "Web, iOS, Android",
          "url": data.install.appUrl,
          "inLanguage": lang,
          "offers": { "@type": "Offer", "price": "0", "priceCurrency": "EUR" },
          "publisher": { "@id": "https://guia.se42.app/#org" },
          "description": seo.desc,
        },
        {
          "@type": "FAQPage",
          "mainEntity": faqItems.map((it) => ({
            "@type": "Question",
            "name": it.q,
            "acceptedAnswer": { "@type": "Answer", "text": it.a },
          })),
        },
      ],
    };
    let el = document.getElementById("se42-jsonld-dynamic");
    if (!el) { el = document.createElement("script"); el.type = "application/ld+json"; el.id = "se42-jsonld-dynamic"; document.head.appendChild(el); }
    el.textContent = JSON.stringify(ld);
  }, [lang, t]);

  /* footer reveal: medir la capa fija y reservar scroll (solo desktop) */
  useEffect(() => {
    const measure = () => {
      const desktop = window.matchMedia("(min-width: 720px)").matches;
      const h = footerRef.current ? footerRef.current.offsetHeight : 0;
      document.documentElement.style.setProperty("--footer-h", desktop && h ? h + "px" : "0px");
    };
    measure();
    const ro = ("ResizeObserver" in window && footerRef.current) ? new ResizeObserver(measure) : null;
    if (ro) ro.observe(footerRef.current);
    window.addEventListener("resize", measure);
    const t2 = setTimeout(measure, 500);
    return () => { window.removeEventListener("resize", measure); if (ro) ro.disconnect(); clearTimeout(t2); };
  }, [lang]);

  /* nav claro→oscuro */
  useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > window.innerHeight * 0.72);
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  /* showcase: la pantalla del teléfono se sincroniza con el paso más cercano
     al centro del viewport — fiable al subir y bajar, y en scroll rápido */
  useEffect(() => {
    const getSteps = () => stepEls.current.filter(Boolean);
    let ticking = false;
    const update = () => {
      ticking = false;
      const steps = getSteps();
      if (!steps.length) return;
      const mid = window.innerHeight / 2;
      let best = 0, bestDist = Infinity;
      steps.forEach((el) => {
        const r = el.getBoundingClientRect();
        const center = r.top + r.height / 2;
        const dist = Math.abs(center - mid);
        const idx = Number(el.getAttribute("data-step"));
        if (dist < bestDist) { bestDist = dist; best = idx; }
      });
      setActive((prev) => (prev === best ? prev : best));
    };
    const onScroll = () => { if (!ticking) { ticking = true; requestAnimationFrame(update); } };
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll, { passive: true });
    update();
    return () => { window.removeEventListener("scroll", onScroll); window.removeEventListener("resize", onScroll); };
  }, [lang]);

  /* reveal on scroll */
  useEffect(() => {
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduce) return;
    document.documentElement.classList.add("reveal-on");
    const els = Array.from(document.querySelectorAll(".reveal"));
    const inView = (el) => {
      const r = el.getBoundingClientRect();
      return r.top < window.innerHeight * 1.05 && r.bottom > -40;
    };
    els.forEach((el) => { if (inView(el)) el.classList.add("is-visible"); });
    if (!("IntersectionObserver" in window)) { els.forEach((el) => el.classList.add("is-visible")); return; }
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("is-visible"); io.unobserve(e.target); } });
    }, { rootMargin: "0px 0px -8% 0px", threshold: 0.12 });
    els.forEach((el) => { if (!el.classList.contains("is-visible")) io.observe(el); });
    return () => io.disconnect();
  }, [lang]);

  return (
    <React.Fragment>
      <div className="intro-veil" aria-hidden="true"></div>
      <Nav t={t} lang={lang} setLang={setLang} scrolled={scrolled} onMenu={() => setMenuOpen(true)} install={install} />
      <MobileMenu t={t} open={menuOpen} onClose={() => setMenuOpen(false)} lang={lang} setLang={setLang} install={install} />

      <div className="scroll-stack">
        <Hero t={t} bg={data.assets.heroBg} video={data.assets.heroVideo} install={install} />
        <Welcome t={t} photo={data.assets.hernan} firma={data.assets.firma} />
        <main className="sheet">
          <Showcase t={t} screens={screens} active={active} registerStep={registerStep} introPhone={data.assets.introPhone} />
          <HowCards t={t} media={data.assets.howMedia} />
          <Band t={t} bg={data.assets.bandBg} />
          <Capabilities t={t} />
          <FAQ t={t} />
        </main>
      </div>

      <div className="footer-spacer" aria-hidden="true" />
      <BottomLayer t={t} logo={data.assets.logoFoot} bg={data.assets.footerBg} begrand={data.assets.begrand} layerRef={footerRef} install={install} />
      {install.iosOpen ? <InstallModal t={t} shots={[data.assets.iosShare, data.assets.iosAdd]} onClose={install.closeIos} /> : null}

      <TweaksPanel title="Tweaks">
        <TweakSection label={lang === "es" ? "Acento" : "Accent"} />
        <TweakColor label={lang === "es" ? "Color" : "Color"} value={tw.accent}
          options={["#E6E779", "#003DCA", "#434635"]} onChange={(v) => setTweak("accent", v)} />
        <TweakRadio label={lang === "es" ? "Palabra serif" : "Serif word"} value={tw.serif}
          options={["italic", "normal"]} onChange={(v) => setTweak("serif", v)} />
        <TweakSection label={lang === "es" ? "Portada" : "Hero"} />
        <TweakSlider label={lang === "es" ? "Oscurecido" : "Darkness"} value={tw.heroVeil}
          min={0.15} max={0.75} step={0.01} onChange={(v) => setTweak("heroVeil", v)} />
        <TweakSlider label={lang === "es" ? "Velado footer" : "Footer veil"} value={tw.footerVeil}
          min={0.5} max={0.97} step={0.01} onChange={(v) => setTweak("footerVeil", v)} />
      </TweaksPanel>
    </React.Fragment>
  );
}

/* Marca la intro ANTES del primer pintado para evitar parpadeo */
(function () {
  try {
    var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    var seen = sessionStorage.getItem("se42_intro_seen") === "1";
    var deepLink = !!window.location.hash && window.location.hash.length > 1;
    if (!reduce && !seen && !deepLink) document.documentElement.classList.add("intro-play");
  } catch (e) {}
})();

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