import * as React from "react"
import {
    type NativeSyntheticEvent,
    type StyleProp,
    StyleSheet,
    type TextInputContentSizeChangeEventData,
    type TextStyle,
} from "react-native"
import {type SharedValue, useAnimatedReaction, useSharedValue} from "react-native-reanimated"

import {
    useBottomSheetToolboxInternalContext,
    useKeyboardHeightSharedValue,
} from "@attio/react-native-bottom-sheet-toolbox"

import {getVerticalBorderWidth} from "../../utils/get-vertical-border-width"
import {getVerticalPadding} from "../../utils/get-vertical-padding"

export interface UseMinOverlayHeightSharedValueArgs {
    textInputStyle?: StyleProp<TextStyle>
    bottomInsetSharedValue: SharedValue<number>
    topInsetSharedValue: SharedValue<number | null>
    minTextInputHeightSharedValue: SharedValue<number | null>
    fallbackLines: number
}

export function useMinOverlayHeightSharedValue({
    textInputStyle,
    topInsetSharedValue,
    bottomInsetSharedValue,
    minTextInputHeightSharedValue,
    fallbackLines,
}: UseMinOverlayHeightSharedValueArgs) {
    const {wrapperHeightSharedValue} = useBottomSheetToolboxInternalContext()

    const flatTextInputStyle = React.useMemo(
        () => StyleSheet.flatten(textInputStyle),
        [textInputStyle]
    )
    const borderWidth = getVerticalBorderWidth(flatTextInputStyle)
    const verticalPadding = getVerticalPadding(flatTextInputStyle)

    /**
     * There is a bug inside React Native which prevents this from being called
     * when it should be: https://github.com/facebook/react-native/issues/47186
     *
     * Hence we try to calculate some meaningful default.
     */
    const lineHeight = Number(flatTextInputStyle.lineHeight ?? 16) * fallbackLines
    const initialContentHeight =
        typeof flatTextInputStyle.minHeight === "number"
            ? Math.max(flatTextInputStyle.minHeight, lineHeight)
            : lineHeight

    const contentHeightSharedValue = useSharedValue(initialContentHeight)
    const onContentSizeChange = React.useCallback(
        (evt: NativeSyntheticEvent<TextInputContentSizeChangeEventData>) => {
            contentHeightSharedValue.set(evt.nativeEvent.contentSize.height)
        },
        []
    )

    const keyboardHeightSharedValue = useKeyboardHeightSharedValue()
    useAnimatedReaction(
        () => {
            const contentHeight = contentHeightSharedValue.get()
            const wrapperHeight = wrapperHeightSharedValue.get()
            const topInset = topInsetSharedValue.get()

            if (contentHeight === 0 || wrapperHeight === null || topInset === null) {
                return null
            }

            const maxOverlayHeight =
                wrapperHeight -
                keyboardHeightSharedValue.get() -
                topInset -
                bottomInsetSharedValue.get()

            const layoutMargins = verticalPadding + borderWidth

            return Math.min(
                contentHeight === 0 ? 0 : contentHeight + layoutMargins || 0,
                maxOverlayHeight
            )
        },
        (result) => {
            minTextInputHeightSharedValue.set(result)
        },
        [
            wrapperHeightSharedValue,
            keyboardHeightSharedValue,
            topInsetSharedValue,
            bottomInsetSharedValue,
            verticalPadding,
            borderWidth,
        ]
    )

    return onContentSizeChange
}
