import type {TextInput} from "react-native-gesture-handler"
import * as React from "react"
import {type TextInputProps, View} from "react-native"
import {useDerivedValue, useSharedValue} from "react-native-reanimated"

import {
    BottomSheetDragGesture,
    BottomSheetToolbox,
    type BottomSheetToolboxProps,
    type BottomSheetToolboxRef,
    CLOSED_SNAP_POINT,
    type SheetPosition,
    type SheetPositionValue,
    useKeyboardAwareSafeAreaBottomInset,
    useLayoutSharedValue,
} from "@attio/react-native-bottom-sheet-toolbox"

import type {BottomSheetToolBoxTextInputBaseProps} from "./types"
import {OverlayTextInput} from "./components/overlay-text-input/overlay-text-input"
import {OverlayTextInputContainer} from "./components/overlay-text-input-container/overlay-text-input-container"

export interface BottomSheetToolboxTextInputRef extends BottomSheetToolboxRef {
    focus: () => void
    blur: () => void
}

export interface BottomSheetToolboxTextInputProps
    extends Pick<
            BottomSheetToolboxProps,
            | "insetTop"
            | "onSnapChange"
            | "onClose"
            | "sheetStyle"
            | "children"
            | "additionalIsReady"
            | "onReadyChange"
            | "backdropComponent"
        >,
        Omit<BottomSheetToolBoxTextInputBaseProps, "style"> {
    multiline?: boolean
    textInputStyle?: TextInputProps["style"]
    ref?: React.ForwardedRef<BottomSheetToolboxTextInputRef> | undefined

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

export function BottomSheetToolboxTextInput({
    insetTop,
    backdropComponent,
    onSnapChange,
    onClose,
    sheetStyle,
    children,
    additionalIsReady: outerAdditionalIsReady,
    multiline = false,
    ref,
    keyboardAwareSafeAreaBottomInsetFallback = 0,
    ...textInputProps
}: BottomSheetToolboxTextInputProps) {
    const {onLayout: onTopInsetLayout, height: topInsetSharedValue} = useLayoutSharedValue()

    const minTextInputHeightSharedValue = useSharedValue<number | null>(null)
    const bottomInsetSharedValue = useKeyboardAwareSafeAreaBottomInset(
        keyboardAwareSafeAreaBottomInsetFallback
    )

    const minSnapPoint = useDerivedValue<SheetPositionValue>(() => {
        const height = minTextInputHeightSharedValue.get()
        const topInset = topInsetSharedValue.get()
        const bottomInset = bottomInsetSharedValue.get()

        if (height === null || topInset === null || bottomInset === null) return null

        return height + topInset + bottomInset
    }, [topInsetSharedValue, bottomInsetSharedValue])

    const additionalIsReady = useDerivedValue(() => {
        const outerReadyAbsolute =
            outerAdditionalIsReady === undefined ||
            (typeof outerAdditionalIsReady === "boolean"
                ? outerAdditionalIsReady
                : outerAdditionalIsReady.get())

        return outerReadyAbsolute && minSnapPoint.get() !== null
    }, [outerAdditionalIsReady])

    const snapPoints = React.useMemo<SheetPosition[]>(
        () =>
            multiline
                ? [CLOSED_SNAP_POINT, minSnapPoint, "100%"]
                : [CLOSED_SNAP_POINT, minSnapPoint],
        [multiline]
    )

    const textInputRef = React.useRef<TextInput>(null)
    const bottomSheetRef = React.useRef<BottomSheetToolboxRef>(null)
    React.useImperativeHandle(
        ref,
        () => ({
            snapToIndex(snapPointIndex: number) {
                bottomSheetRef.current?.snapToIndex(snapPointIndex)
            },
            expand() {
                bottomSheetRef.current?.expand()
            },
            close() {
                bottomSheetRef.current?.close()
            },
            getCurrentSnapIndex() {
                return bottomSheetRef.current?.getCurrentSnapIndex() || null
            },
            focus() {
                textInputRef.current?.focus()
            },
            blur() {
                textInputRef.current?.blur()
            },
        }),
        []
    )

    return (
        <BottomSheetToolbox
            ref={bottomSheetRef}
            snapPoints={snapPoints}
            initialSnapPointIndex={1}
            backdropComponent={backdropComponent}
            overlayComponent={
                <BottomSheetDragGesture id="text-input">
                    <OverlayTextInputContainer
                        keyboardAwareSafeAreaBottomInsetFallback={
                            keyboardAwareSafeAreaBottomInsetFallback
                        }
                        minTextInputHeightSharedValue={minTextInputHeightSharedValue}
                        topInsetSharedValue={topInsetSharedValue}
                        bottomInsetSharedValue={bottomInsetSharedValue}
                    >
                        <OverlayTextInput
                            ref={textInputRef}
                            {...textInputProps}
                            multiline={multiline}
                            topInsetSharedValue={topInsetSharedValue}
                            bottomInsetSharedValue={bottomInsetSharedValue}
                            minTextInputHeightSharedValue={minTextInputHeightSharedValue}
                        />
                    </OverlayTextInputContainer>
                </BottomSheetDragGesture>
            }
            sheetStyle={sheetStyle}
            additionalIsReady={additionalIsReady}
            {...(insetTop && {insetTop})}
            {...(onSnapChange && {onSnapChange})}
            {...(onClose && {onClose})}
        >
            <View onLayout={onTopInsetLayout} pointerEvents="box-none">
                {children}
            </View>
        </BottomSheetToolbox>
    )
}
BottomSheetToolboxTextInput.displayName = "BottomSheetToolboxTextInput"
