import type * as React from "react"
import {type StyleProp, StyleSheet, type ViewStyle} from "react-native"
import Animated, {
    type SharedValue,
    useAnimatedReaction,
    useAnimatedStyle,
    useDerivedValue,
} from "react-native-reanimated"

import {useBottomSheetToolboxInternalContext} from "../context"
import {
    type UseFooterBottomPositionSharedValueArgs,
    useFooterBottomPositionSharedValue,
    useKeyboardAwareSafeAreaBottomInset,
    useLayoutSharedValue,
} from "../hooks"

const styles = StyleSheet.create({
    container: {
        bottom: 0,
        opacity: 0,
        position: "absolute",
        width: "100%",
    },
})

interface BottomSheetOverlayFooterProps
    extends React.PropsWithChildren,
        UseFooterBottomPositionSharedValueArgs {
    /**
     * Forces the internally calculated footer height to some other SharedValue.
     */
    footerHeightSharedValue?: SharedValue<number | null>

    /**
     * It's very common for footers to have an animated bottom inset, e.g.
     * for neatly avoiding the keyboard.
     *
     * However, as the default footerHeightSharedValue is derived from layout
     * calculations this means the consumer is unable to fluctuate the footer's
     * height whilst preserving smooth animations.
     *
     * To get round this the consumer could manage and pass in their own
     * footerHeightSharedValue, but this is a hassle. To make life a little
     * easier we allow the consumer to instead pass in their own
     * bottomInsetSharedValue.
     *
     * By default, we set this to the keyboard aware safe area bottom inset.
     * However, this can be disabled entirely by passing in null.
     */
    bottomInsetSharedValue?: SharedValue<number> | null

    /**
     * The fallback inset value when using the default bottomInsetSharedValue
     * behavior.
     */
    keyboardAwareSafeAreaBottomInsetFallback?: number

    style?: StyleProp<Pick<ViewStyle, "backgroundColor">>
}

export function BottomSheetOverlayFooter({
    children,
    footerHeightSharedValue: outerFooterHeightSharedValue,
    bottomInsetSharedValue: outerBottomInsetSharedValue,
    style,
    keyboardAwareSafeAreaBottomInsetFallback = 0,
    ...hookArgs
}: BottomSheetOverlayFooterProps) {
    const {isReadySharedValue, footerHeightSharedValue} = useBottomSheetToolboxInternalContext()
    const {height: layoutFooterHeightSharedValue, onLayout: onFooterLayout} = useLayoutSharedValue<
        number | null
    >(null)

    const KeyboardAwareSafeAreaBottomInsetSharedValue = useKeyboardAwareSafeAreaBottomInset(
        keyboardAwareSafeAreaBottomInsetFallback
    )
    const bottomInsetSharedValue = useDerivedValue(
        () =>
            outerBottomInsetSharedValue === undefined
                ? KeyboardAwareSafeAreaBottomInsetSharedValue.get()
                : (outerBottomInsetSharedValue?.get() ?? 0),
        [outerBottomInsetSharedValue, KeyboardAwareSafeAreaBottomInsetSharedValue]
    )

    useAnimatedReaction(
        () => {
            const result =
                outerFooterHeightSharedValue === undefined
                    ? layoutFooterHeightSharedValue.get()
                    : outerFooterHeightSharedValue.get()

            if (result === null) return null

            return result + bottomInsetSharedValue.get()
        },
        (value) => {
            footerHeightSharedValue.set(value)
        },
        [outerFooterHeightSharedValue, layoutFooterHeightSharedValue]
    )

    const bottomSharedValue = useFooterBottomPositionSharedValue(hookArgs)

    const animatedStyle = useAnimatedStyle(() => {
        const bottom = bottomSharedValue.get()
        if (bottom === null || !isReadySharedValue.get()) return {}

        const bottomInset = bottomInsetSharedValue.get()

        return {
            opacity: 1,
            paddingBottom: bottomInset,
            transform: [{translateY: -bottom}],
        }
    }, [isReadySharedValue, bottomSharedValue])

    return (
        <Animated.View style={[styles.container, style, animatedStyle]}>
            <Animated.View onLayout={onFooterLayout}>{children}</Animated.View>
        </Animated.View>
    )
}
