import * as React from "react"
import {useMergeRefs} from "react-merge-refs"
import {
    type LayoutChangeEvent,
    type NativeScrollEvent,
    type NativeSyntheticEvent,
    ScrollView,
    type ScrollViewProps,
} from "react-native"

import {
    BottomSheetScrollGestureDetector,
    useBottomSheetScrollGestureDetectorConnector,
} from "@attio/react-native-bottom-sheet-toolbox"

interface FlashListScrollComponentProps extends ScrollViewProps {
    ref?: React.ForwardedRef<ScrollView>
}

function makeFlashListScrollComponent(inverted: boolean) {
    return function FlashListScrollComponent({
        onScroll,
        onLayout,
        onContentSizeChange,
        ref,
        ...p
    }: FlashListScrollComponentProps) {
        const {
            scrollOffsetYSharedValue,
            scrollRef,
            scrollContentHeightSharedValue,
            scrollLayoutHeightSharedValue,
        } = useBottomSheetScrollGestureDetectorConnector<ScrollView>()

        const innerOnScroll = React.useCallback(
            (evt: NativeSyntheticEvent<NativeScrollEvent>) => {
                onScroll?.(evt)
                scrollOffsetYSharedValue.set(evt.nativeEvent.contentOffset.y)
                scrollLayoutHeightSharedValue.set(evt.nativeEvent.layoutMeasurement.height)
                scrollContentHeightSharedValue.set(evt.nativeEvent.contentSize.height)
            },
            [
                onScroll,
                scrollOffsetYSharedValue,
                scrollLayoutHeightSharedValue,
                scrollContentHeightSharedValue,
            ]
        )

        const innerOnLayout = React.useCallback(
            (evt: LayoutChangeEvent) => {
                onLayout?.(evt)
                scrollLayoutHeightSharedValue.set(evt.nativeEvent.layout.height)
            },
            [onLayout, scrollLayoutHeightSharedValue]
        )

        const innerOnContentSizeChange = React.useCallback(
            (w: number, h: number) => {
                onContentSizeChange?.(w, h)
                scrollContentHeightSharedValue.set(h)
            },
            [onContentSizeChange, scrollContentHeightSharedValue]
        )

        const refs = useMergeRefs([scrollRef, ref])

        return (
            <BottomSheetScrollGestureDetector
                scrollRef={scrollRef}
                scrollOffsetYSharedValue={scrollOffsetYSharedValue}
                scrollContentHeightSharedValue={scrollContentHeightSharedValue}
                scrollLayoutHeightSharedValue={scrollLayoutHeightSharedValue}
                inverted={inverted}
            >
                <ScrollView
                    ref={refs}
                    onScroll={innerOnScroll}
                    onContentSizeChange={innerOnContentSizeChange}
                    onLayout={innerOnLayout}
                    scrollEventThrottle={1}
                    {...p}
                />
            </BottomSheetScrollGestureDetector>
        )
    }
}

export const FlashListScrollComponent = makeFlashListScrollComponent(false)

export const InvertedFlashListScrollComponent = makeFlashListScrollComponent(true)
