import { useEffect, useState } from "react";
import Lenis from "@studio-freight/lenis";
import { usePathname, useSearchParams } from "next/navigation";

import { useStore } from "@/store";

import useLayoutEffect from "./useIsomorphicLayoutEffect";
import useRaf from "./useRaf";

type EasingFunction = (t: number) => number;
type Orientation = "vertical" | "horizontal";
type GestureOrientation = "vertical" | "horizontal" | "both";

export interface LenisOptions {
  wrapper?: Window | HTMLElement;
  content?: HTMLElement;
  wheelEventsTarget?: Window | HTMLElement;
  eventsTarget?: Window | HTMLElement;
  smoothWheel?: boolean;
  smoothTouch?: boolean;
  syncTouch?: boolean;
  syncTouchLerp?: number;
  touchInertiaMultiplier?: number;
  duration?: number;
  easing?: EasingFunction;
  lerp?: number;
  infinite?: boolean;
  orientation?: Orientation;
  gestureOrientation?: GestureOrientation;
  touchMultiplier?: number;
  wheelMultiplier?: number;
  normalizeWheel?: boolean;
  autoResize?: boolean;
}

const defaultOptions = {
  duration: 1,
};

export default function useLenis(options: LenisOptions = defaultOptions) {
  const lenis = useStore.use.lenis();
  const setLenis = useStore.use.setLenis();
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const [scrollProgress, setScrollProgress] = useState(0);

  useLayoutEffect(() => {
    window.history.scrollRestoration = "manual";

    const lenis = new Lenis({ ...options });
    setLenis(lenis);

    const resize = setInterval(() => {
      lenis.resize();
    }, 150);

    return () => {
      clearInterval(resize);
      lenis.destroy();
      setLenis(null);
    };
  }, [options, setLenis]);

  useEffect(() => {
    if (lenis) lenis.scrollTo(0, { immediate: true });
  }, [pathname, searchParams, lenis]);

  useEffect(() => {
    if (lenis) {
      const handleScroll = () => {
        const progress = lenis.scroll / lenis.limit;
        const roundedProgress = parseFloat(progress.toFixed(3));
        setScrollProgress(roundedProgress);
      };
      lenis.on("scroll", handleScroll);
      return () => lenis.off("scroll", handleScroll);
    }
  }, [lenis]);

  useRaf((time) => {
    lenis?.raf(time);
  });

  return { scrollProgress };
}
