// Cinematic layer — letterbox, SplitText reveal, Ken Burns, film grain, magnetic CTAs, scramble.
// All effects respect prefers-reduced-motion and are toggleable via tweaks.

const REDUCED = typeof window !== "undefined" &&
  window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;

// ── Lenis smooth scroll ───────────────────────────────────────────────────
let __lenis = null;
function ensureLenis(on) {
  if (REDUCED) return;
  if (on && !__lenis && window.Lenis) {
    __lenis = new window.Lenis({ duration: 1.15, easing: (x) => Math.min(1, 1.001 - Math.pow(2, -10 * x)), smoothWheel: true });
    const raf = (t) => { __lenis && __lenis.raf(t); requestAnimationFrame(raf); };
    requestAnimationFrame(raf);
    if (window.ScrollTrigger && window.gsap) {
      __lenis.on("scroll", window.ScrollTrigger.update);
      window.gsap.ticker.add((time) => __lenis.raf(time * 1000));
      window.gsap.ticker.lagSmoothing(0);
    }
  } else if (!on && __lenis) {
    __lenis.destroy(); __lenis = null;
  }
}

// ── SplitText line reveal hook ────────────────────────────────────────────
function useSplitReveal(ref, deps, opts = {}) {
  React.useEffect(() => {
    if (REDUCED) return;
    const el = ref.current;
    if (!el || !window.gsap || !window.SplitText) return;
    let split;
    let cancelled = false;

    const run = () => {
      if (cancelled || !el) return;
      try {
        split = new window.SplitText(el, { type: "lines,words", mask: "lines", linesClass: "split-line" });
        window.gsap.set(el, { opacity: 1 });
        window.gsap.from(split.lines, {
          yPercent: 110,
          duration: opts.duration || 1.05,
          ease: opts.ease || "expo.out",
          stagger: opts.stagger || 0.08,
          delay: opts.delay || 0,
        });
      } catch (e) {}
    };

    if (document.fonts && document.fonts.ready) {
      document.fonts.ready.then(run);
    } else {
      run();
    }

    return () => {
      cancelled = true;
      try { split && split.revert(); } catch (e) {}
    };
  }, deps);
}

// ── Magnetic effect ───────────────────────────────────────────────────────
function bindMagnetic(el, strength = 0.35) {
  if (REDUCED || !el || !window.gsap) return () => {};
  const handleMove = (e) => {
    const r = el.getBoundingClientRect();
    const cx = r.left + r.width / 2;
    const cy = r.top + r.height / 2;
    const dx = (e.clientX - cx) * strength;
    const dy = (e.clientY - cy) * strength;
    window.gsap.to(el, { x: dx, y: dy, duration: 0.45, ease: "power3.out" });
  };
  const handleLeave = () => {
    window.gsap.to(el, { x: 0, y: 0, duration: 0.6, ease: "elastic.out(1, 0.4)" });
  };
  el.addEventListener("mousemove", handleMove);
  el.addEventListener("mouseleave", handleLeave);
  return () => {
    el.removeEventListener("mousemove", handleMove);
    el.removeEventListener("mouseleave", handleLeave);
    window.gsap && window.gsap.set(el, { clearProps: "transform" });
  };
}

function useMagnetic(selector, enabled, strength = 0.3) {
  React.useEffect(() => {
    if (!enabled || REDUCED) return;
    const hover = window.matchMedia("(hover: hover) and (pointer: fine)").matches;
    if (!hover) return;
    const els = document.querySelectorAll(selector);
    const cleaners = [];
    els.forEach((el) => cleaners.push(bindMagnetic(el, strength)));
    return () => cleaners.forEach((c) => c());
  }, [selector, enabled, strength]);
}

// ── Scramble text on a word ───────────────────────────────────────────────
function ScrambleWord({ text, enabled, delay = 1.6, duration = 1.2 }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!enabled || REDUCED || !ref.current || !window.gsap || !window.ScrambleTextPlugin) return;
    const el = ref.current;
    el.textContent = text;
    const tween = window.gsap.to(el, {
      delay,
      duration,
      ease: "none",
      scrambleText: {
        text,
        chars: "01//{}<>$#&%@!?+=",
        revealDelay: 0.2,
        speed: 0.45,
      },
    });
    return () => tween && tween.kill();
  }, [text, enabled, delay, duration]);

  // Hover re-scramble
  const onEnter = () => {
    if (!enabled || REDUCED || !ref.current || !window.gsap || !window.ScrambleTextPlugin) return;
    window.gsap.to(ref.current, {
      duration: 0.9,
      ease: "none",
      scrambleText: { text, chars: "01//{}<>$#&%@!?+=", revealDelay: 0.15, speed: 0.4 },
    });
  };

  return <span className="scramble" ref={ref} onMouseEnter={onEnter}>{text}</span>;
}

// ── Letterbox bars (animated in on hero) ──────────────────────────────────
function Letterbox({ enabled }) {
  React.useEffect(() => {
    if (!enabled) return;
    document.documentElement.setAttribute("data-letterbox", "on");
    return () => document.documentElement.removeAttribute("data-letterbox");
  }, [enabled]);

  if (!enabled) return null;
  return (
    <React.Fragment>
      <div className="letterbox letterbox--top" aria-hidden="true"></div>
      <div className="letterbox letterbox--bottom" aria-hidden="true"></div>
    </React.Fragment>
  );
}

// ── Film grain overlay ────────────────────────────────────────────────────
function Grain({ enabled, intensity = 0.18 }) {
  if (!enabled) return null;
  return <div className="grain" style={{ opacity: intensity }} aria-hidden="true"></div>;
}

// ── Cursor (text-cursor on portrait) ──────────────────────────────────────
function CinemaCursor({ enabled }) {
  const ref = React.useRef(null);
  const labelRef = React.useRef(null);
  const [active, setActive] = React.useState(false);
  const [label, setLabel] = React.useState("");

  React.useEffect(() => {
    if (!enabled || REDUCED) return;
    const hover = window.matchMedia("(hover: hover) and (pointer: fine)").matches;
    if (!hover) return;

    let x = 0, y = 0, tx = 0, ty = 0;
    const onMove = (e) => { tx = e.clientX; ty = e.clientY; };
    const tick = () => {
      x += (tx - x) * 0.22;
      y += (ty - y) * 0.22;
      if (ref.current) {
        ref.current.style.transform = `translate3d(${x}px, ${y}px, 0) translate(-50%, -50%)`;
      }
      raf = requestAnimationFrame(tick);
    };
    let raf = requestAnimationFrame(tick);

    const enter = (e) => {
      const el = e.target.closest("[data-cursor]");
      if (!el) return;
      setActive(true);
      setLabel(el.getAttribute("data-cursor") || "");
    };
    const leave = (e) => {
      if (!e.target.closest || !e.target.closest("[data-cursor]")) {
        setActive(false);
      }
    };

    document.addEventListener("mousemove", onMove);
    document.addEventListener("mouseover", enter);
    document.addEventListener("mouseout", leave);
    document.documentElement.setAttribute("data-cursor-on", "true");

    return () => {
      cancelAnimationFrame(raf);
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseover", enter);
      document.removeEventListener("mouseout", leave);
      document.documentElement.removeAttribute("data-cursor-on");
    };
  }, [enabled]);

  if (!enabled || REDUCED) return null;
  return (
    <div ref={ref} className={"cinema-cursor " + (active ? "is-active" : "")} aria-hidden="true">
      <span ref={labelRef} className="cinema-cursor__label">{label}</span>
    </div>
  );
}

Object.assign(window, {
  useSplitReveal, useMagnetic, ScrambleWord,
  Letterbox, Grain, CinemaCursor, ensureLenis, REDUCED_MOTION: REDUCED,
});
