"use client";

import { usePathname } from "next/navigation";
import { useEffect } from "react";

// Selectors for elements that should animate in on scroll (scoped to <main>).
const TARGETS = [
  "h1", "h2", "h3", "h4",
  ".eyebrow", ".eyebrow-light",
  "p",
  ".btn-primary", ".btn-ghost", ".link-arrow", ".chip",
  '[class*="card"]', '[class*="__tile"]', '[class*="__item"]',
  '[class*="__pillar"]', '[class*="__step"]', '[class*="__cat"]',
]
  .map((s) => `main ${s}`)
  .join(",");

// Sections that manage their own motion / must not be hidden.
const EXCLUDE = ".home-hero, .jbanner, .nav, .footer, nav, footer, header";

export default function ScrollReveal() {
  const pathname = usePathname();

  useEffect(() => {
    if (typeof window === "undefined") return;
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;

    let cleanup = () => {};
    const id = window.requestAnimationFrame(() => {
      const all = Array.from(document.querySelectorAll<HTMLElement>(TARGETS)).filter(
        (el) => !el.closest(EXCLUDE)
      );

      // Keep only the outermost targets so a card animates as one unit
      // (its inner heading/paragraph don't animate separately).
      const set = new Set(all);
      const targets = all.filter((el) => {
        let p = el.parentElement;
        while (p) {
          if (set.has(p)) return false;
          p = p.parentElement;
        }
        return true;
      });

      // Small stagger between siblings that share a parent.
      const byParent = new Map<Element, HTMLElement[]>();
      targets.forEach((el) => {
        const parent = el.parentElement;
        if (!parent) return;
        const arr = byParent.get(parent) ?? [];
        arr.push(el);
        byParent.set(parent, arr);
      });
      byParent.forEach((arr) => {
        arr.forEach((el, idx) => {
          el.style.setProperty("--reveal-delay", `${Math.min(idx * 0.08, 0.4)}s`);
        });
      });

      const observer = new IntersectionObserver(
        (entries) => {
          entries.forEach((entry) => {
            if (entry.isIntersecting) {
              entry.target.classList.add("is-visible");
              observer.unobserve(entry.target);
            }
          });
        },
        { rootMargin: "0px 0px -8% 0px", threshold: 0.08 }
      );

      const variantFor = (el: HTMLElement) => {
        const cls = el.className || "";
        if (el.matches(".eyebrow, .eyebrow-light")) return "reveal--left";
        if (
          /card|__tile|__item|__pillar|__step|__cat/.test(
            typeof cls === "string" ? cls : ""
          )
        ) {
          return "reveal--zoom";
        }
        return "reveal--up";
      };

      targets.forEach((el) => {
        el.classList.add("reveal", variantFor(el));
        const rect = el.getBoundingClientRect();
        const inView = rect.top < window.innerHeight && rect.bottom > 0;
        if (inView) {
          // Already visible on load — reveal instantly, no hidden flash.
          el.classList.add("is-visible");
        } else {
          observer.observe(el);
        }
      });

      cleanup = () => observer.disconnect();
    });

    return () => {
      window.cancelAnimationFrame(id);
      cleanup();
    };
  }, [pathname]);

  return null;
}
