// Main app — ties everything together. Cursor preview, nav, tweaks.
const { useState: useStateA, useEffect: useEffectA, useRef: useRefA } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#c0392b",
  "accentName": "rojo cine",
  "display": "serif",
  "typography": "studio",
  "bg": "paper",
  "stripCounter": false,
  "showIntro": true,
  "lightboxLayout": "filmstrip",
  "cardOrientation": "vertical",
  "cardOrder": "normal",
  "collageVariant": "spread",
  "motionLayout": "stack"
}/*EDITMODE-END*/;

function Nav({ active, onJump }) {
  const [photoOpen, setPhotoOpen] = useStateA(false);
  const [menuPos, setMenuPos] = useStateA({ top: 0, left: 0 });
  const [mobileOpen, setMobileOpen] = useStateA(false);
  const closeTimer = useRefA(null);
  const triggerRef = useRefA(null);

  const photoChildren = [
    { id: "live_music",  label: "SHOWS" },
    { id: "portraits",   label: "RETRATOS" },
    { id: "documentary", label: "DOCUMENTAL" },
  ];
  const photoIds = photoChildren.map((c) => c.id);
  const photoActive = photoIds.includes(active);

  const links = [
    { id: "motion",   label: "CINE / VIDEO" },
    { id: "about",    label: "SOBRE MÍ" },
    { id: "kiosco",   label: "KIOSCO" },
  ];

  // Lock scroll while fullscreen mobile menu is open
  useEffectA(() => {
    if (!mobileOpen) return;
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    const onKey = (e) => { if (e.key === "Escape") setMobileOpen(false); };
    window.addEventListener("keydown", onKey);
    return () => {
      document.body.style.overflow = prev;
      window.removeEventListener("keydown", onKey);
    };
  }, [mobileOpen]);

  const handleMobileJump = (id) => {
    setMobileOpen(false);
    // Defer slightly to let menu close animation start before scrolling
    setTimeout(() => onJump(id), 60);
  };

  const openMenu = () => {
    if (closeTimer.current) clearTimeout(closeTimer.current);
    if (triggerRef.current) {
      const r = triggerRef.current.getBoundingClientRect();
      setMenuPos({ top: r.bottom + 14, left: r.left - 14 });
    }
    setPhotoOpen(true);
  };
  const scheduleClose = () => {
    if (closeTimer.current) clearTimeout(closeTimer.current);
    closeTimer.current = setTimeout(() => setPhotoOpen(false), 180);
  };

  useEffectA(() => {
    if (!photoOpen) return;
    const onScrollOrResize = () => {
      if (triggerRef.current) {
        const r = triggerRef.current.getBoundingClientRect();
        setMenuPos({ top: r.bottom + 14, left: r.left - 14 });
      }
    };
    window.addEventListener("scroll", onScrollOrResize, { passive: true });
    window.addEventListener("resize", onScrollOrResize);
    return () => {
      window.removeEventListener("scroll", onScrollOrResize);
      window.removeEventListener("resize", onScrollOrResize);
    };
  }, [photoOpen]);

  return (
    <nav className="nav">
      <a href="#top" className="nav__mark mono" onClick={(e) => { e.preventDefault(); onJump("top"); }}>
        <span className="nav__mark-bullet" /> MAPA LÓPEZ
      </a>
      <button
        className={`nav__burger mono ${mobileOpen ? "is-open" : ""}`}
        aria-label={mobileOpen ? "Cerrar menú" : "Abrir menú"}
        aria-expanded={mobileOpen}
        onClick={() => setMobileOpen((v) => !v)}
      >
        <span className="nav__burger-lines" aria-hidden="true">
          <span /><span /><span />
        </span>
        <span className="nav__burger-label">{mobileOpen ? "CERRAR" : "MENÚ"}</span>
      </button>
      <ul className="nav__links mono">
        <li
          className="nav__dropdown"
          onMouseEnter={openMenu}
          onMouseLeave={scheduleClose}
        >
          <button
            ref={triggerRef}
            className={`nav__dropdown-trigger ${photoActive ? "is-active" : ""}`}
            onClick={() => {
              onJump(photoChildren[0].id);
              setPhotoOpen(false);
            }}
            aria-expanded={photoOpen}
          >
            FOTOGRAFÍA
            <span className="nav__caret">{photoOpen ? "▴" : "▾"}</span>
          </button>
          {photoOpen && (
            <div
              className="nav__menu"
              style={{ top: menuPos.top, left: menuPos.left }}
              onMouseEnter={openMenu}
              onMouseLeave={scheduleClose}
            >
              <div className="nav__menu-label muted">/ CATEGORÍAS</div>
              {photoChildren.map((c, i) => (
                <a
                  key={c.id}
                  href={`#${c.id}`}
                  className={`nav__menu-item ${active === c.id ? "is-active" : ""}`}
                  onClick={(e) => {
                    e.preventDefault();
                    setPhotoOpen(false);
                    onJump(c.id);
                  }}
                >
                  <span className="nav__menu-n">{String(i + 1).padStart(2, "0")}</span>
                  <span>{c.label}</span>
                  <span className="nav__menu-arrow">→</span>
                </a>
              ))}
            </div>
          )}
        </li>
        {links.map((l) => (
          <li key={l.id}>
            <a
              href={`#${l.id}`}
              className={active === l.id ? "is-active" : ""}
              onClick={(e) => { e.preventDefault(); onJump(l.id); }}
            >{l.label}</a>
          </li>
        ))}
      </ul>

      <div
        className={`nav__mobile ${mobileOpen ? "is-open" : ""}`}
        aria-hidden={!mobileOpen}
      >
        <div className="nav__mobile-inner">
          <div className="nav__mobile-label mono">/ NAVEGACIÓN</div>
          <ul className="nav__mobile-list">
            <li className="nav__mobile-section">
              <div className="nav__mobile-section-label serif">FOTOGRAFÍA</div>
              {photoChildren.map((c) => (
                <a
                  key={c.id}
                  href={`#${c.id}`}
                  className={`nav__mobile-sublink mono ${active === c.id ? "is-active" : ""}`}
                  onClick={(e) => { e.preventDefault(); handleMobileJump(c.id); }}
                >
                  <span className="nav__mobile-dot" aria-hidden="true">•</span>
                  <span>{c.label}</span>
                  <span className="nav__mobile-arrow">→</span>
                </a>
              ))}
            </li>
            {links.map((l) => (
              <li key={l.id}>
                <a
                  href={`#${l.id}`}
                  className={`nav__mobile-link serif ${active === l.id ? "is-active" : ""}`}
                  onClick={(e) => { e.preventDefault(); handleMobileJump(l.id); }}
                >
                  <span className="nav__mobile-link-text">{l.label}</span>
                </a>
              </li>
            ))}
          </ul>
          <div className="nav__mobile-foot mono">
            <span>MAPA LÓPEZ</span>
            <span className="muted">— FOTOGRAFÍA & CINE</span>
          </div>
        </div>
      </div>
    </nav>
  );
}

function CursorPreview({ item, pos }) {
  if (!item) return null;
  return (
    <div
      className="cursor-preview"
      style={{ transform: `translate(${pos.x}px, ${pos.y}px)` }}
    >
      <img src={item.src} alt="" />
    </div>
  );
}

function TweaksPanel({ settings, setSettings, onClose }) {
  const update = (patch) => {
    const next = { ...settings, ...patch };
    setSettings(next);
    window.parent.postMessage({ type: "__edit_mode_set_keys", edits: patch }, "*");
  };
  const accents = [
    { n: "rojo cine", v: "#c0392b" },
    { n: "ámbar", v: "#c98a3b" },
    { n: "cobalto", v: "#2f4b7c" },
    { n: "verde táctico", v: "#4a6b3a" },
    { n: "violeta", v: "#5e3a7a" },
    { n: "ninguno", v: "#111111" },
  ];
  return (
    <div className="tweaks">
      <div className="tweaks__head mono">
        <span>TWEAKS</span>
        <button onClick={onClose}>✕</button>
      </div>
      <div className="tweaks__body mono">
        <div className="tweaks__group">
          <div className="tweaks__label">ACENTO</div>
          <div className="tweaks__row tweaks__row--wrap">
            {accents.map((a) => (
              <button
                key={a.n}
                className={settings.accent === a.v ? "is-active" : ""}
                onClick={() => update({ accent: a.v, accentName: a.n })}
                style={{ "--swatch": a.v }}
              >
                <span className="tweaks__swatch" />
                {a.n}
              </button>
            ))}
          </div>
        </div>
        <div className="tweaks__group">
          <div className="tweaks__label">FONDO</div>
          <div className="tweaks__row tweaks__row--wrap">
            {[
              { v: "paper",   n: "paper",   sw: "oklch(0.97 0.003 80)"  },
              { v: "bone",    n: "bone",    sw: "oklch(0.95 0.015 80)"  },
              { v: "gallery", n: "gallery", sw: "oklch(0.97 0.003 240)" },
              { v: "mat",     n: "mat",     sw: "oklch(0.87 0.005 80)"  },
              { v: "sand",    n: "sand",    sw: "oklch(0.94 0.025 75)"  },
              { v: "olive",   n: "olive",   sw: "oklch(0.94 0.020 120)" },
            ].map((o) => (
              <button
                key={o.v}
                className={(settings.bg || "paper") === o.v ? "is-active" : ""}
                onClick={() => update({ bg: o.v })}
                style={{ "--swatch": o.sw }}
              >
                <span className="tweaks__swatch" />
                {o.n}
              </button>
            ))}
          </div>
        </div>
        <div className="tweaks__group">
          <div className="tweaks__label">CONTADOR GALERÍA</div>
          <div className="tweaks__row">
            <button
              className={settings.stripCounter ? "is-active" : ""}
              onClick={() => update({ stripCounter: !settings.stripCounter })}
            >{settings.stripCounter ? "VISIBLE" : "OCULTO"}</button>
          </div>
        </div>
        <div className="tweaks__group">
          <div className="tweaks__label">INTRO</div>
          <div className="tweaks__row">
            <button
              className={settings.showIntro ? "is-active" : ""}
              onClick={() => update({ showIntro: !settings.showIntro })}
            >{settings.showIntro ? "ACTIVO" : "DESACTIVADO"}</button>
            <button onClick={() => window.location.reload()}>RECARGAR</button>
          </div>
        </div>
      </div>
    </div>
  );
}

function App() {
  const [settings, setSettings] = useStateA(TWEAK_DEFAULTS);
  const [tweaksOpen, setTweaksOpen] = useStateA(false);
  const [introDone, setIntroDone] = useStateA(!TWEAK_DEFAULTS.showIntro);
  const [, forceTick] = useStateA(0);

  // If the intro is disabled, data.js still needs to be loaded so the
  // gallery has something to render. The Intro normally injects it.
  useEffectA(() => {
    if (window.MAPA_DATA) return;
    if (document.querySelector('script[data-mapa-data]')) return;
    const s = document.createElement("script");
    s.src = "components/data.js?v=6";
    s.async = false;
    s.dataset.mapaData = "true";
    s.onload = () => forceTick((n) => n + 1);
    document.head.appendChild(s);
  }, []);

  // Lock body scroll while intro is active
  useEffectA(() => {
    if (!introDone && TWEAK_DEFAULTS.showIntro) {
      const prev = document.body.style.overflow;
      document.body.style.overflow = "hidden";
      return () => { document.body.style.overflow = prev; };
    }
  }, [introDone]);
  const [lightbox, setLightbox] = useStateA(null);
  const [hoverItem, setHoverItem] = useStateA(null);
  const [cursorPos, setCursorPos] = useStateA({ x: 0, y: 0 });
  const [active, setActive] = useStateA("live_music");

  // edit mode wiring
  useEffectA(() => {
    const onMsg = (e) => {
      if (!e.data || !e.data.type) return;
      if (e.data.type === "__activate_edit_mode") setTweaksOpen(true);
      if (e.data.type === "__deactivate_edit_mode") setTweaksOpen(false);
    };
    window.addEventListener("message", onMsg);
    window.parent.postMessage({ type: "__edit_mode_available" }, "*");
    return () => window.removeEventListener("message", onMsg);
  }, []);

  // apply settings to :root
  useEffectA(() => {
    const r = document.documentElement;
    r.dataset.theme = "light";
    r.dataset.display = settings.display;
    r.dataset.typography = settings.typography || "studio";
    r.dataset.bg = settings.bg || "paper";
    r.dataset.bio = "dropcap";
    r.dataset.social = "inline";
    r.dataset.navChrome = "solid";
    r.dataset.stripCounter = settings.stripCounter ? "true" : "false";
    r.dataset.lightboxLayout = settings.lightboxLayout || "filmstrip";
    r.dataset.cardOrientation = settings.cardOrientation || "vertical";
    r.dataset.cardOrder = settings.cardOrder || "normal";
    r.dataset.collageVariant = settings.collageVariant || "spread";
    r.dataset.motionLayout = settings.motionLayout || "grid";
    r.dataset.lightboxClose = "keyboard";
    r.dataset.lightboxCursor = "arrow";
    r.dataset.lightboxBg = "ink";
    r.style.setProperty("--accent", settings.accent);
  }, [settings]);

  // cursor preview
  useEffectA(() => {
    const move = (e) => setCursorPos({ x: e.clientX, y: e.clientY });
    window.addEventListener("mousemove", move);
    return () => window.removeEventListener("mousemove", move);
  }, []);

  // nav scroll state — used by RULE chrome variant
  useEffectA(() => {
    const onScroll = () => {
      document.documentElement.dataset.navScrolled = window.scrollY > 8 ? "true" : "false";
    };
    onScroll();
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  // scroll-spy — pick the section whose top has most recently passed the
  // reference line (25% from viewport top). Predictable, no flicker.
  useEffectA(() => {
    const ids = ["live_music", "portraits", "documentary", "motion", "about", "kiosco"];
    let rafId = 0;
    const update = () => {
      rafId = 0;
      const line = window.innerHeight * 0.25;
      let current = ids[0];
      for (const id of ids) {
        const el = document.getElementById(id);
        if (!el) continue;
        const top = el.getBoundingClientRect().top;
        if (top - line <= 0) current = id;
      }
      // near page bottom — force last
      if (window.innerHeight + window.scrollY >= document.body.scrollHeight - 80) {
        current = ids[ids.length - 1];
      }
      setActive((prev) => (prev === current ? prev : current));
    };
    const onScroll = () => {
      if (!rafId) rafId = requestAnimationFrame(update);
    };
    update();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      if (rafId) cancelAnimationFrame(rafId);
    };
  }, [introDone]);

  const jump = (id) => {
    if (id === "top") {
      window.scrollTo({ top: 0, behavior: "smooth" });
      return;
    }
    const el = document.getElementById(id);
    if (el) {
      const y = el.getBoundingClientRect().top + window.scrollY - 40;
      window.scrollTo({ top: y, behavior: "smooth" });
    }
  };

  const D = window.MAPA_DATA;

  return (
    <>
      {!introDone && settings.showIntro && (
        <Intro onDone={() => setIntroDone(true)} />
      )}

      {D && <Nav active={active} onJump={jump} />}

      {D && <main id="top" className="main">
        <GalleryStrip
          id="live_music"
          label="SHOWS"
          items={D.LIVE_MUSIC}
          onOpen={setLightbox}
          onHover={setHoverItem}
          onLeave={() => setHoverItem(null)}
        />
        <GalleryStrip
          id="portraits"
          label="RETRATOS"
          items={D.PORTRAITS}
          onOpen={setLightbox}
          onHover={setHoverItem}
          onLeave={() => setHoverItem(null)}
        />
        <GalleryStrip
          id="documentary"
          label="DOCUMENTAL"
          items={D.DOCUMENTARY}
          onOpen={setLightbox}
          onHover={setHoverItem}
          onLeave={() => setHoverItem(null)}
        />
        <Motion items={D.MOTION} />
        <About />
        <Kiosco />
        <Footer />
      </main>}

      <CursorPreview item={hoverItem} pos={cursorPos} />
      <Lightbox state={lightbox} onClose={() => setLightbox(null)} />
      {tweaksOpen && (
        <TweaksPanel
          settings={settings}
          setSettings={setSettings}
          onClose={() => {
            setTweaksOpen(false);
            window.parent.postMessage({ type: "__edit_mode_exit" }, "*");
          }}
        />
      )}
    </>
  );
}

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