'use client'
import { useGSAP } from '@gsap/react'
import gsap from 'gsap'
import { SplitText } from 'gsap/SplitText'
import { ScrollTrigger, GSDevTools } from 'gsap/all'
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useRef, type ReactNode } from 'react'

gsap.registerPlugin(useGSAP)
gsap.registerPlugin(ScrollTrigger)
gsap.registerPlugin(SplitText)
gsap.registerPlugin(GSDevTools)
const GsapContext = createContext<{
  addAnimation: (
    animation: gsap.core.TimelineChild,
    position: gsap.Position
  ) => void,
  resetTimeline: () => void,
  resumeTimeline: () => void,
  getScroller: () => Element | Window | null
} | null>(null)

export function useGsapContext() {
  return useContext(GsapContext)
}

export const useTimeLine = (dep:any,all?:boolean) => {
  const gsapContext = useGsapContext()
    useEffect(() => {
      if (dep instanceof Array && all) {
        let acc = true;
        let allDepsSatisfied = dep.reduce((p,c) => c !== undefined && p ,acc )
        if (allDepsSatisfied) {
          gsapContext?.resumeTimeline()
        }
      } else {
        if (dep) {
          gsapContext?.resumeTimeline()
        }
      }
    },[dep])
  useLayoutEffect(() => {
    return () => {
      gsapContext?.resetTimeline()
    }
  },[])
}

export default function GsapProvider({ children }: { children: ReactNode }) {
  const tl = useRef<gsap.core.Timeline | null>(null)
  const scrollerRef = useRef<Element | Window | null>(null)
  const getScroller = useCallback(() => {
    // const cached = scrollerRef.current
    // if (!cached || (cached instanceof Element && !document.contains(cached))) {
      let scrollers = document.querySelectorAll('[data-slot="scroll-area-viewport"]')
      if (scrollers.length < 1) {
        scrollerRef.current = window
      } else {
        let scrollerArray = Array.from(scrollers.values()).sort((a,b) => {
          const s1 = a as HTMLDivElement;
          const s2 = b as HTMLDivElement;
          // using bitwise not (~~) to coerce NaN values to 0
          const aPriority = ~~Number(s1.dataset?.scrollerPriority)
          const bPriority = ~~Number(s2.dataset?.scrollerPriority)
          return aPriority - bPriority;
        })
        let prioScroller = scrollerArray.pop();
        scrollerRef.current = prioScroller || window;
      }

    // }
    return scrollerRef.current
  }, [])
  useGSAP(() => {
    if (!tl.current) {
      tl.current = gsap.timeline({ paused: true })
    }
    return () => { console.log("gsap cleanup") }
  })

  const addAnimation = useCallback((animation: gsap.core.TimelineChild, position: gsap.Position) => {
    console.log("add animation to:", position, tl.current !== undefined)
    tl.current?.add(animation, position);
  },[])
  const resetTimeline = useCallback(() => {
    tl.current?.kill()
    tl.current?.revert()
    ScrollTrigger.getAll().forEach(st => st.kill())
    tl.current = gsap.timeline({paused:true})
  },[])
  const resumeTimeline = useCallback(() => {
    console.log("resuming timeline:",tl.current)
    tl.current?.resume()
  },[])
  return (
    <GsapContext.Provider value={{ addAnimation, resetTimeline, resumeTimeline, getScroller }}>
      {children}
    </GsapContext.Provider>
  )
}
