/* global gsap, ScrollTrigger, Lenis */

/**
 * Evo Creation — library-driven motion layer.
 * Runs after React mounts. Wires Lenis (smooth scroll) into ScrollTrigger,
 * then registers all the scroll-driven animations.
 */
(function () {
  if (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;

  const start = () => {
    if (!window.gsap || !window.ScrollTrigger || !window.Lenis) {
      requestAnimationFrame(start);
      return;
    }
    gsap.registerPlugin(ScrollTrigger);

    /* ---------------------------------------------------------
       Lenis smooth scroll — drive ScrollTrigger from Lenis ticks
       --------------------------------------------------------- */
    const lenis = new Lenis({
      duration: 1.4,
      easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
      smoothWheel: true,
      wheelMultiplier: 0.85,
      touchMultiplier: 1.4,
      lerp: 0.08,
    });
    document.documentElement.classList.add("lenis", "lenis-smooth");
    lenis.on("scroll", ScrollTrigger.update);
    gsap.ticker.add((time) => lenis.raf(time * 1000));
    gsap.ticker.lagSmoothing(0);
    window.__lenis = lenis;

    // anchor links → smooth scroll
    document.addEventListener("click", (e) => {
      const a = e.target.closest('a[href^="#"]');
      if (!a) return;
      const id = a.getAttribute("href");
      if (id.length < 2) return;
      const target = document.querySelector(id);
      if (!target) return;
      e.preventDefault();
      lenis.scrollTo(target, { offset: -40, duration: 1.6 });
    });

    /* ---------------------------------------------------------
       Image mask-wipe reveal — scrub the curtain off as section enters
       --------------------------------------------------------- */
    gsap.utils.toArray(".media-reveal").forEach((el) => {
      const after = document.createElement("div");
      after.className = "mr-curtain";
      el.appendChild(after);
      const img = el.querySelector("img");
      if (img) gsap.set(img, { scale: 1.14 });
      gsap.timeline({
        scrollTrigger: { trigger: el, start: "top 88%", end: "top 32%", scrub: 1.2 },
      })
        .to(after, { scaleX: 0, ease: "none" }, 0)
        .to(img || {}, { scale: 1, ease: "none" }, 0);
    });

    /* ---------------------------------------------------------
       Line-by-line reveals — use fromTo so lines stay visible
       by default and only briefly hide during their own animation.
       --------------------------------------------------------- */
    gsap.utils.toArray(".line-reveal").forEach((el) => {
      const lines = el.querySelectorAll(".line > .inner");
      if (!lines.length) return;
      ScrollTrigger.create({
        trigger: el,
        start: "top 92%",
        once: true,
        onEnter: () => {
          gsap.fromTo(lines,
            { yPercent: 110, rotate: 2 },
            { yPercent: 0, rotate: 0, duration: 1.4, ease: "expo.out", stagger: 0.14, clearProps: "transform" }
          );
        },
      });
    });

    /* ---------------------------------------------------------
       Image parallax — image drifts inside its container as you scroll
       --------------------------------------------------------- */
    gsap.utils.toArray(".parallax-frame > img, .parallax-frame > .px-img").forEach((img) => {
      gsap.fromTo(img,
        { yPercent: -10 },
        {
          yPercent: 8, ease: "none",
          scrollTrigger: { trigger: img.parentElement, start: "top bottom", end: "bottom top", scrub: 1.2 },
        }
      );
    });

    /* ---------------------------------------------------------
       Hero — keep title slightly behind as user scrolls (parallax depth)
       --------------------------------------------------------- */
    const heroTitle = document.querySelector(".hero-title");
    if (heroTitle) {
      gsap.to(heroTitle, {
        yPercent: 28, opacity: 0.4, ease: "none",
        scrollTrigger: { trigger: ".hero", start: "top top", end: "bottom top", scrub: 1.2 },
      });
    }

    /* ---------------------------------------------------------
       SplitType — char-by-char reveal on big display headlines
       --------------------------------------------------------- */
    if (window.SplitType) {
      gsap.utils.toArray(".hero-title, .featured-title, .h-big").forEach((el) => {
        // Don't double-split LineReveal headlines (they have .inner already)
        if (el.querySelector(".inner")) return;
        try {
          const split = new SplitType(el, { types: "chars", tagName: "span" });
          if (split.chars && split.chars.length) {
            gsap.from(split.chars, {
              yPercent: 110, opacity: 0,
              duration: 0.9, ease: "expo.out", stagger: 0.018,
              scrollTrigger: { trigger: el, start: "top 88%", once: true },
            });
          }
        } catch (err) { /* ignore */ }
      });
    }

    /* ---------------------------------------------------------
       Continuous portfolio loop — handled in JSX/CSS as a marquee
       --------------------------------------------------------- */

    /* ---------------------------------------------------------
       Pinned services — sticky photo column, list scrolls past
       --------------------------------------------------------- */
    const servicesSection = document.querySelector(".services");
    if (servicesSection && window.innerWidth >= 900) {
      // Done by CSS sticky now; ScrollTrigger to update active state.
      const photoPin = servicesSection.querySelector(".services-photo-pin img");
      const items = gsap.utils.toArray(".services-grid > .service");
      items.forEach((item, i) => {
        ScrollTrigger.create({
          trigger: item, start: "top 60%", end: "bottom 40%",
          onEnter: () => setActiveService(i),
          onEnterBack: () => setActiveService(i),
        });
      });
      function setActiveService(i) {
        const all = document.querySelectorAll(".services-pin-img");
        all.forEach((img, idx) => {
          img.classList.toggle("is-active", idx === i);
        });
      }
    }

    /* ---------------------------------------------------------
       Floating ambient marker — a brass orb that floats with parallax
       --------------------------------------------------------- */
    const orb = document.querySelector(".ambient-orb");
    if (orb) {
      gsap.to(orb, {
        y: 600, x: -120, rotate: 240,
        ease: "none",
        scrollTrigger: { trigger: "body", start: "top top", end: "bottom bottom", scrub: 2 },
      });
    }

    /* ---------------------------------------------------------
       Section fade-in on enter (replace .reveal hand-roll)
       --------------------------------------------------------- */
    gsap.utils.toArray(".studio-copy, .contact-wrap, .num-cell, .work, .service").forEach((el) => {
      gsap.from(el, {
        y: 36, opacity: 0,
        duration: 1.2, ease: "expo.out",
        scrollTrigger: { trigger: el, start: "top 86%", once: true },
      });
    });

    /* ---------------------------------------------------------
       Custom cursor — soft ring + dot, GSAP-eased
       --------------------------------------------------------- */
    const cursor = document.getElementById("cursor");
    if (cursor && !matchMedia("(hover: none)").matches) {
      document.body.classList.add("has-cursor");
      const ring = cursor.querySelector(".cursor-ring");
      const dot = cursor.querySelector(".cursor-dot");
      const xToRing = gsap.quickTo(ring, "x", { duration: 0.6, ease: "expo.out" });
      const yToRing = gsap.quickTo(ring, "y", { duration: 0.6, ease: "expo.out" });
      const xToDot = gsap.quickTo(dot, "x", { duration: 0.18, ease: "expo.out" });
      const yToDot = gsap.quickTo(dot, "y", { duration: 0.18, ease: "expo.out" });

      window.addEventListener("pointermove", (e) => {
        xToRing(e.clientX); yToRing(e.clientY);
        xToDot(e.clientX); yToDot(e.clientY);
      });

      // hover state — ring grows, dot shrinks
      document.addEventListener("pointerover", (e) => {
        const t = e.target.closest("a, button, [data-cursor]");
        if (t) {
          gsap.to(ring, { scale: 1.8, borderColor: "rgba(155, 125, 76, 0.9)", duration: 0.6, ease: "expo.out" });
          gsap.to(dot, { scale: 0, duration: 0.4 });
        }
      });
      document.addEventListener("pointerout", (e) => {
        const t = e.target.closest("a, button, [data-cursor]");
        if (t) {
          gsap.to(ring, { scale: 1, borderColor: "rgba(29, 26, 21, 0.55)", duration: 0.6, ease: "expo.out" });
          gsap.to(dot, { scale: 1, duration: 0.4 });
        }
      });
    }

    /* ---------------------------------------------------------
       Magnetic CTAs — buttons pull toward the cursor
       --------------------------------------------------------- */
    gsap.utils.toArray(".btn-solid, .btn-on-dark.solid, .btn-on-dark").forEach((btn) => {
      const strength = 0.32;
      btn.addEventListener("pointermove", (e) => {
        const r = btn.getBoundingClientRect();
        const dx = (e.clientX - (r.left + r.width / 2)) * strength;
        const dy = (e.clientY - (r.top + r.height / 2)) * strength;
        gsap.to(btn, { x: dx, y: dy, duration: 0.5, ease: "expo.out" });
      });
      btn.addEventListener("pointerleave", () => {
        gsap.to(btn, { x: 0, y: 0, duration: 0.7, ease: "elastic.out(1, 0.6)" });
      });
    });

    /* ---------------------------------------------------------
       Marquee — drive translate with GSAP for buttery loop
       --------------------------------------------------------- */
    gsap.utils.toArray(".marquee-track").forEach((track) => {
      // Remove the CSS-driven animation in favor of GSAP
      track.style.animation = "none";
      const half = track.scrollWidth / 2;
      gsap.to(track, {
        x: -half, duration: 60, repeat: -1, ease: "none",
      });
    });

    /* ---------------------------------------------------------
       ScrollTrigger refresh once everything has measured
       --------------------------------------------------------- */
    requestAnimationFrame(() => ScrollTrigger.refresh());
    setTimeout(() => ScrollTrigger.refresh(), 600);
    setTimeout(() => ScrollTrigger.refresh(), 1800);
  };

  // Wait until React mounts the components
  const waitForReact = () => {
    if (document.querySelector(".hero")) start();
    else setTimeout(waitForReact, 60);
  };
  waitForReact();
})();
