"use client";

import { useEffect } from "react";
import { usePathname } from "next/navigation";
import Lenis from "lenis";
import { MotionConfig, frame, cancelFrame, useReducedMotion } from "motion/react";

/**
 * One Lenis instance for the whole app, driven from Framer Motion's frame loop
 * so scroll linked animations read the same scroll value Lenis just wrote,
 * rather than lagging a frame behind it.
 *
 * This also carries the app wide MotionConfig. `reducedMotion="user"` drops
 * transform animations for anyone who has asked their system for less motion,
 * while leaving opacity alone.
 *
 * Note for anyone adding animation to this site: never branch the rendered
 * markup on `useReducedMotion()`. It returns null on the server and the real
 * preference after mount, so a structural branch guarantees a hydration
 * mismatch. Branch on `transition` and event handlers, which do not reach the
 * server rendered HTML, and leave `initial`, `style` and element type alone.
 */
export function SmoothScroll({ children }: { children: React.ReactNode }) {
  const reduced = useReducedMotion();
  const pathname = usePathname();

  useEffect(() => {
    if (reduced) return;

    const lenis = new Lenis({
      duration: 1.05,
      easing: (t: number) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
      touchMultiplier: 1.6,
      // Native scrolling on touch stays out of the way of browser gestures.
      syncTouch: false,
    });

    const update = (data: { timestamp: number }) => lenis.raf(data.timestamp);
    frame.update(update, true);

    return () => {
      cancelFrame(update);
      lenis.destroy();
    };
  }, [reduced]);

  // App Router keeps the scroll position on soft navigation in some cases.
  // Force the top of the new page so a route change never lands mid section.
  useEffect(() => {
    window.scrollTo(0, 0);
  }, [pathname]);

  return <MotionConfig reducedMotion="user">{children}</MotionConfig>;
}
