import {GestureDetector} from "react-native-gesture-handler"
import {
    type ScrollHandler,
    useAnimatedRef,
    useAnimatedScrollHandler,
    useSharedValue,
} from "react-native-reanimated"

import {type UseBottomSheetScrollGestureArgs, useBottomSheetScrollGesture} from "../hooks"

export function BottomSheetScrollGestureDetector<T>({
    children,
    ...rest
}: React.PropsWithChildren<UseBottomSheetScrollGestureArgs<T>>) {
    const gesture = useBottomSheetScrollGesture(rest)

    return <GestureDetector gesture={gesture}>{children}</GestureDetector>
}

interface ScrollEventListeners<
    ScrollContext extends Record<string, unknown> = Record<string, unknown>,
> {
    onScroll?: ScrollHandler<ScrollContext>
    onBeginDrag?: ScrollHandler<ScrollContext>
    onEndDrag?: ScrollHandler<ScrollContext>
    onMomentumBegin?: ScrollHandler<ScrollContext>
    onMomentumEnd?: ScrollHandler<ScrollContext>
}

export function useBottomSheetScrollGestureDetectorConnector<
    // biome-ignore lint/suspicious/noExplicitAny: not useful to type
    T extends React.Component<object, object, any>,
    ScrollContext extends Record<string, unknown> = Record<string, unknown>,
>(scrollDefaults: ScrollEventListeners<ScrollContext> = {}) {
    const scrollRef = useAnimatedRef<T>()

    const scrollOffsetYSharedValue = useSharedValue(0)
    const scrollContentHeightSharedValue = useSharedValue<number | null>(null)
    const scrollLayoutHeightSharedValue = useSharedValue<number | null>(null)
    const scrollHandler = useAnimatedScrollHandler<ScrollContext>(
        {
            onScroll: (event, context) => {
                scrollDefaults.onScroll?.(event, context)
                scrollOffsetYSharedValue.set(event.contentOffset.y)
                scrollContentHeightSharedValue.set(event.contentSize.height)
                scrollLayoutHeightSharedValue.set(event.layoutMeasurement.height)
            },
            onBeginDrag: (event, context) => {
                scrollDefaults.onBeginDrag?.(event, context)
            },
            onEndDrag: (event, context) => {
                scrollDefaults.onEndDrag?.(event, context)
            },
            onMomentumBegin: (event, context) => {
                scrollDefaults.onMomentumBegin?.(event, context)
            },
            onMomentumEnd: (event, context) => {
                scrollDefaults.onMomentumEnd?.(event, context)
            },
        },
        [
            scrollDefaults.onScroll,
            scrollDefaults.onBeginDrag,
            scrollDefaults.onEndDrag,
            scrollDefaults.onMomentumBegin,
            scrollDefaults.onMomentumEnd,
        ]
    )

    return {
        scrollRef,
        scrollHandler,
        scrollOffsetYSharedValue,
        scrollContentHeightSharedValue,
        scrollLayoutHeightSharedValue,
    }
}
