/* ===========================================================
   1 A 1 — App: idioma, Tweaks (acento re-tematiza), reveal
   =========================================================== */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#4a8fac",
  "motion": true,
  "cursor": true,
  "startLang": "es"
}/*EDITMODE-END*/;

/* Cursor moderno — punto central instantáneo + anillo externo con retraso físico (lerp) */
function CustomCursor() {
  const dotRef = React.useRef(null);
  const ringRef = React.useRef(null);

  React.useEffect(() => {
    const mq = window.matchMedia("(hover: hover) and (pointer: fine)");
    if (!mq.matches) return;
    const root = document.documentElement;
    root.classList.add("cursor-custom-active");

    const dot = dotRef.current;
    const ring = ringRef.current;

    const mouse = { x: -100, y: -100 };
    const dotPos = { x: -100, y: -100 };
    const ringPos = { x: -100, y: -100 };

    let raf;

    const loop = () => {
      // Easing rápido para el punto central (mantiene precisión)
      dotPos.x += (mouse.x - dotPos.x) * 0.4;
      dotPos.y += (mouse.y - dotPos.y) * 0.4;

      // Easing más lento para el anillo (efecto fluidez física)
      ringPos.x += (mouse.x - ringPos.x) * 0.16;
      ringPos.y += (mouse.y - ringPos.y) * 0.16;

      if (dot) {
        dot.style.transform = `translate(${dotPos.x}px, ${dotPos.y}px)`;
      }
      if (ring) {
        ring.style.transform = `translate(${ringPos.x}px, ${ringPos.y}px)`;
      }

      raf = requestAnimationFrame(loop);
    };

    const onMove = (e) => {
      mouse.x = e.clientX;
      mouse.y = e.clientY;

      dot.classList.add("show");
      ring.classList.add("show");

      const hot = e.target.closest && e.target.closest("a,button,input,textarea,select,label,.gw-piece,.gfilter,[role=tab],image-slot,.contact-channel,.lang button");

      if (hot) {
        dot.classList.add("hot");
        ring.classList.add("hot");
      } else {
        dot.classList.remove("hot");
        ring.classList.remove("hot");
      }
    };

    const onDown = () => {
      dot.classList.add("down");
      ring.classList.add("down");
    };

    const onUp = () => {
      dot.classList.remove("down");
      ring.classList.remove("down");
    };

    const onOut = (e) => {
      if (!e.relatedTarget) {
        dot.classList.remove("show");
        ring.classList.remove("show");
      }
    };

    window.addEventListener("mousemove", onMove, { passive: true });
    window.addEventListener("mousedown", onDown);
    window.addEventListener("mouseup", onUp);
    window.addEventListener("mouseout", onOut);
    raf = requestAnimationFrame(loop);

    return () => {
      cancelAnimationFrame(raf);
      root.classList.remove("cursor-custom-active");
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mousedown", onDown);
      window.removeEventListener("mouseup", onUp);
      window.removeEventListener("mouseout", onOut);
    };
  }, []);

  return (
    <React.Fragment>
      <div className="cursor-dot" ref={dotRef} aria-hidden="true"></div>
      <div className="cursor-ring" ref={ringRef} aria-hidden="true"></div>
    </React.Fragment>
  );
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  const [lang, setLang] = React.useState(() => localStorage.getItem("1a1-lang") || TWEAK_DEFAULTS.startLang);

  const touched = React.useRef(false);
  React.useEffect(() => {
    localStorage.setItem("1a1-lang", lang);
    document.documentElement.lang = lang;
  }, [lang]);
  const onSetLang = (l) => { touched.current = true; setLang(l); };
  React.useEffect(() => { if (!touched.current) setLang(t.startLang); }, [t.startLang]);

  // ---- Router: rutas reales por pestaña (/trabajo, /industrias, /herramientas-gratuitas) ----
  const normalizePath = (p) => (p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p);
  const [route, setRoute] = React.useState(() => normalizePath(window.location.pathname));
  React.useEffect(() => {
    const scrollToHashOrTop = (hash) => {
      requestAnimationFrame(() => requestAnimationFrame(() => {
        if (hash) {
          const el = document.querySelector(hash);
          if (el) { el.scrollIntoView(); return; }
        }
        window.scrollTo(0, 0);
      }));
    };
    const onPop = () => {
      setRoute(normalizePath(window.location.pathname));
      scrollToHashOrTop(window.location.hash);
    };
    const onClick = (e) => {
      if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
      const a = e.target.closest && e.target.closest("a");
      if (!a) return;
      const raw = a.getAttribute("href");
      if (!raw || a.target === "_blank" || a.hasAttribute("download")) return;
      let url;
      try { url = new URL(a.href, window.location.origin); } catch (_) { return; }
      if (url.origin !== window.location.origin) return; // enlace externo
      const cur = normalizePath(window.location.pathname);
      const dest = normalizePath(url.pathname);
      if (dest === cur) {
        if (url.hash) return;                 // misma página con ancla → scroll nativo
        e.preventDefault();                   // misma página sin ancla (logo) → subir
        window.scrollTo({ top: 0 });
        return;
      }
      e.preventDefault();                     // cambio de pestaña sin recargar
      window.history.pushState({}, "", url.pathname + url.hash);
      setRoute(dest);
      scrollToHashOrTop(url.hash);
    };
    window.addEventListener("popstate", onPop);
    document.addEventListener("click", onClick);
    return () => {
      window.removeEventListener("popstate", onPop);
      document.removeEventListener("click", onClick);
    };
  }, []);

  // Acento = color principal de toda la página
  React.useEffect(() => {
    document.documentElement.style.setProperty("--accent", t.accent);
  }, [t.accent]);

  // Movimiento (líneas + ticker)
  React.useEffect(() => {
    document.documentElement.classList.toggle("motion-off", !t.motion);
  }, [t.motion]);

  const copy = window.SITE[lang];

  // Reveal on scroll — estado base visible; se oculta para animar sólo con JS.
  React.useEffect(() => {
    let scheduled = false;
    const check = () => {
      scheduled = false;
      const vh = window.innerHeight || document.documentElement.clientHeight;
      document.querySelectorAll("[data-reveal]:not(.in), .reveal-title:not(.in)").forEach((el) => {
        if (el.getBoundingClientRect().top < vh * 0.92) el.classList.add("in");
      });
    };
    const onScroll = () => { if (scheduled) return; scheduled = true; (window.requestAnimationFrame || setTimeout)(check); };
    check();
    document.documentElement.classList.add("reveal-on");
    check();
    const timers = [60, 200, 500, 1000].map((ms) => setTimeout(check, ms));
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll, { passive: true });
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      timers.forEach(clearTimeout);
    };
  }, [lang, route]);

  return (
    <React.Fragment>
      <Nav t={copy} lang={lang} setLang={onSetLang} route={route} />
      <main>
        {route === "/trabajo" ? (
          <React.Fragment>
            <WorkExhibition t={copy} />
            <Gallery t={copy} />
          </React.Fragment>
        ) : route === "/industrias" ? (
          <ComingSoon soon={copy.soon} data={copy.soon.industrias} />
        ) : route === "/herramientas-gratuitas" ? (
          <ComingSoon soon={copy.soon} data={copy.soon.tools} />
        ) : (
          <React.Fragment>
            <Hero t={copy} />
            <Why t={copy} />
            <Services t={copy} />
            <WebIndex t={copy} />
            <WebListIndex t={copy} />
            <Audit t={copy} />
            <Contact t={copy} />
          </React.Fragment>
        )}
      </main>
      <Footer t={copy} />

      <ChatFab />
      {t.cursor ? <CustomCursor /> : null}

      <TweaksPanel title={copy.tweaks.title}>
        <TweakSection label={copy.tweaks.colorSection} />
        <TweakColor label={copy.tweaks.accentColor} value={t.accent}
          options={["#4a8fac", "#5d7c95", "#4fa39d", "#b08a5e", "#9678ab"]}
          onChange={(v) => setTweak("accent", v)} />
        <TweakSection label={copy.tweaks.motionSection} />
        <TweakToggle label={copy.tweaks.motionLabel} value={t.motion}
          onChange={(v) => setTweak("motion", v)} />
        <TweakToggle label={copy.tweaks.cursorLabel} value={t.cursor}
          onChange={(v) => setTweak("cursor", v)} />
        <TweakSection label={copy.tweaks.langSection} />
        <TweakRadio label={copy.tweaks.langLabel} value={t.startLang}
          options={[{ value: "es", label: "Español" }, { value: "en", label: "English" }]}
          onChange={(v) => setTweak("startLang", v)} />
      </TweaksPanel>
    </React.Fragment>
  );
}

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

// La app ya montó: avisa al preloader para que la ventana (portal) se abra
// sobre la página real y no sobre el esqueleto de carga.
requestAnimationFrame(function () {
  if (typeof window.dismissPreloader === "function") window.dismissPreloader();
});
