"use client";

import { useEffect, useRef } from "react";
import { usePathname } from "next/navigation";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { ScrollSmoother } from "gsap/ScrollSmoother";

gsap.registerPlugin(ScrollTrigger, ScrollSmoother);

const MOBILE_BREAKPOINT = 768;

export function ScrollSmootherProvider() {
  const smootherRef = useRef<ScrollSmoother | null>(null);
  const pathname = usePathname();
  const isFirstRenderRef = useRef(true);

  useEffect(() => {
    const prefersReduced = window.matchMedia(
      "(prefers-reduced-motion: reduce)",
    ).matches;
    const isMobile = window.innerWidth < MOBILE_BREAKPOINT;

    if (prefersReduced) return;

    const smoother = ScrollSmoother.create({
      wrapper: "#smooth-wrapper",
      content: "#smooth-content",
      smooth: isMobile ? 0.6 : 1.2,
      effects: !isMobile,
      normalizeScroll: !isMobile,
      ignoreMobileResize: true,
    });

    smootherRef.current = smoother;

    return () => {
      smoother.kill();
      smootherRef.current = null;
    };
  }, []);

  // The layout that mounts this provider persists across client-side route
  // changes, so the ScrollSmoother instance above is created once and never
  // recreated when navigating between pages. Its internal scroll position
  // and measured content height stay tied to whatever page was on screen
  // before the navigation. If the next page is a different height, the
  // stale height/position pairing snaps into place the instant the new page
  // paints — most visible as the fixed header's active-nav-item background
  // jumping instead of easing, since it briefly renders against the old,
  // now-incorrect scroll transform. Resetting scroll on every pathname
  // change and refreshing ScrollTrigger's measurements once the new page has
  // painted keeps the smoother in sync with what's actually on screen.
  useEffect(() => {
    if (isFirstRenderRef.current) {
      isFirstRenderRef.current = false;
      return;
    }

    const smoother = smootherRef.current;
    if (!smoother) {
      return;
    }

    smoother.scrollTo(0, false);

    const refreshFrame = requestAnimationFrame(() => {
      ScrollTrigger.refresh();
    });

    return () => cancelAnimationFrame(refreshFrame);
  }, [pathname]);

  return null;
}
