import {
    type PointerEvent,
    useEffect,
    useState,
    type FC,
    useRef
} from "react";
import {
    TouchableWithoutFeedback,
    useWindowDimensions,
    PanResponder,
    Platform,
    Animated,
    Easing,
    View
} from "react-native";
import type ISnackBarProps from "./type";
import stylesheet, {
    getSnackBarType,
    useStyles
} from "./stylesheet";
import {
    NCoreUIKitTheme
} from "../../core/hooks";
import {
    useSafeAreaInsets
} from "react-native-safe-area-context";
import {
    type SafePointerEvent,
    safeGlobal
} from "../../types";
import {
    X as XIcon
} from "lucide-react-native";
import {
    Portal
} from "../../helpers/portalize";
import {
    windowHeight
} from "../../utils";
import Button from "../button";
import Text from "../text";

const SnackBar: FC<ISnackBarProps> = ({
    isCloseOnPressActionButton = true,
    closeAnimationDelay = 350,
    openAnimationDelay = 200,
    spreadBehaviour = "free",
    autoCloseDelay = 5000,
    contentContainerStyle,
    isCloseOnPress = true,
    isFullWidth = false,
    isShowAction = true,
    icon: CustomIcon,
    isInlineSafeArea,
    type = "neutral",
    customTheme,
    children,
    onClosed,
    subTitle,
    onPress,
    action,
    style,
    title,
    id
}) => {
    const {
        radiuses,
        colors,
        spaces
    } = NCoreUIKitTheme.useContext(customTheme);

    const {
        top
    } = useSafeAreaInsets();

    const [
        isMeasured,
        setIsMeasured
    ] = useState(false);

    const {
        width: windowWidth
    } = useWindowDimensions();

    const contentHeight = useRef<number>(windowHeight);

    const transformAnim = useRef(new Animated.Value(-contentHeight.current + -top + -spaces.spacingSm)).current;
    const opacityAnim = useRef(new Animated.Value(0)).current;

    const currentType = getSnackBarType({
        type
    });

    const {
        contentContainer: contentContainerDynamicStyle,
        containerObject: containerObjectDynamicStyle,
        iconContainer: iconContainerDynamicStyle,
        container: containerDynamicStyle,
        subTitle: subTitleDynamicStyle,
        action: actionDynamicStyle,
        title: titleDynamicStyle
    } = useStyles({
        isInlineSafeArea,
        safeAreaTop: top,
        spreadBehaviour,
        currentType,
        isFullWidth,
        radiuses,
        colors,
        spaces,
        type
    });

    useEffect(() => {
        if(isMeasured) {
            transformAnim.setValue(-contentHeight.current + -top + -spaces.spacingSm);

            Animated.parallel([
                Animated.timing(opacityAnim, {
                    duration: openAnimationDelay,
                    easing: Easing.linear,
                    useNativeDriver: true,
                    toValue: 1
                }),
                Animated.timing(transformAnim, {
                    duration: openAnimationDelay,
                    easing: Easing.linear,
                    useNativeDriver: true,
                    toValue: 0
                })
            ]).start();

            setTimeout(() => {
                closeAnimation();
            }, autoCloseDelay);
        }
    }, [
        isMeasured
    ]);

    const panResponder = useRef(
        PanResponder.create({
            onMoveShouldSetPanResponderCapture: (_, gestureState) => {
                const {
                    dy
                } = gestureState;

                if(Math.abs(dy) < 20) {
                    return false;
                }

                return true;
            },
            onPanResponderTerminationRequest: () => false,
            onPanResponderMove: (_, gestureState) => {
                const {
                    moveY,
                    y0,
                    dy
                } = gestureState;

                if(moveY > y0) {
                    return;
                }

                const op = moveY / y0;

                opacityAnim.setValue(op);
                transformAnim.setValue(dy);
            },
            onStartShouldSetPanResponder: () => false,
            onPanResponderEnd: (_, gestureState) => {
                const {
                    moveY,
                    y0,
                    vy
                } = gestureState;

                if(vy < -1) {
                    closeAnimation();
                    return;
                }

                if(y0 - moveY > 25) {
                    closeAnimation();
                    return;
                }

                Animated.parallel([
                    Animated.timing(opacityAnim, {
                        duration: openAnimationDelay,
                        easing: Easing.linear,
                        useNativeDriver: true,
                        toValue: 1
                    }),
                    Animated.timing(transformAnim, {
                        duration: openAnimationDelay,
                        easing: Easing.linear,
                        useNativeDriver: true,
                        toValue: 0
                    })
                ]).start();
            },
            onShouldBlockNativeResponder: () => true
        })
    ).current;

    const closeAnimation = (_onClosed?: (props: {
        id: string;
    }) => void) => {
        Animated.parallel([
            Animated.timing(transformAnim, {
                toValue: -contentHeight.current + -top + -spaces.spacingSm,
                duration: closeAnimationDelay,
                useNativeDriver: true,
                easing: Easing.linear
            }),
            Animated.timing(opacityAnim, {
                duration: closeAnimationDelay,
                easing: Easing.linear,
                useNativeDriver: true,
                toValue: 0
            })
        ]).start(({
            finished
        }) => {
            if(finished) {
                if(onClosed) onClosed({
                    id
                });

                if(_onClosed) _onClosed({
                    id
                });
            }
        });
    };

    const renderIcon = () => {
        if(!CustomIcon) {
            return null;
        }

        return <View
            style={[
                stylesheet.iconContainer,
                iconContainerDynamicStyle
            ]}
        >
            <CustomIcon
                color="default"
                size={18}
            />
        </View>;
    };

    const renderContent = () => {
        return <View
            style={[
                contentContainerStyle,
                stylesheet.contentContainer,
                contentContainerDynamicStyle
            ]}
        >
            <Text
                style={{
                    ...stylesheet.title,
                    ...titleDynamicStyle
                }}
                numberOfLines={3}
            >
                {title}
            </Text>
            {
                subTitle ?
                    <Text
                        style={{
                            ...stylesheet.subTitle,
                            ...subTitleDynamicStyle
                        }}
                        variant="labelSmallSize"
                        numberOfLines={2}
                        color="low"
                    >
                        {subTitle}
                    </Text>
                :
                    null
            }
        </View>;
    };

    const renderAction = () => {
        if(!isShowAction) {
            return null;
        }

        return <Button
            icon={({
                color
            }) => {
                if(action?.title) {
                    return null;
                }

                return <XIcon
                    color={colors.content.icon[color ? color : "default"]}
                    size={18}
                />;
            }}
            title={action && action.title ? action.title : undefined}
            onPress={() => {
                if(isCloseOnPressActionButton) closeAnimation();

                if(action && action.onPress) action.onPress({
                    closeAnimation: ({
                        onClosed: _onClosed
                    }) => closeAnimation(_onClosed)
                });
            }}
            style={{
                ...action?.style,
                ...actionDynamicStyle
            }}
            isCustomPadding={true}
            spreadBehaviour="free"
            variant="ghost"
            type="neutral"
            size="small"
        />;
    };

    const renderContainer = () => {
        return <View
            style={[
                stylesheet.containerObject,
                containerObjectDynamicStyle
            ]}
        >
            {renderIcon()}
            {renderContent()}
            {renderAction()}
        </View>;
    };

    return <Portal
        name="snack-bar-system"
    >
        <Animated.View
            {...(Platform.OS === "web" ? {} : panResponder.panHandlers)}
            style={[
                style,
                stylesheet.container,
                containerDynamicStyle,
                {
                    width: isFullWidth ? windowWidth : (spreadBehaviour === "stretch" ? windowWidth - (spaces.spacingMd * 2) : undefined),
                    transform: [
                        {
                            translateY: transformAnim
                        }
                    ],
                    opacity: opacityAnim
                }
            ]}
            onPointerDown={Platform.OS === "web" ? (evt) => {
                const nativeEvt = evt as unknown as PointerEvent;
                const startY = nativeEvt.clientY;

                let lastY = startY;
                let lastTime = Date.now();
                let velocityY = 0;

                const handlePointerMove = (moveEvt: SafePointerEvent) => {
                    const dy = moveEvt.clientY - startY;

                    if (dy > 0) return; // sadece yukarı swipe

                    const now = Date.now();
                    const dt = now - lastTime;
                    if (dt > 0) velocityY = (moveEvt.clientY - lastY) / dt;
                    lastY = moveEvt.clientY;
                    lastTime = now;

                    const op = Math.max(0, 1 + (dy / contentHeight.current));
                    opacityAnim.setValue(op);
                    transformAnim.setValue(dy);
                };

                const handlePointerUp = () => {
                    safeGlobal.removeEventListener("pointermove", handlePointerMove);
                    safeGlobal.removeEventListener("pointerup", handlePointerUp);

                    const dy = lastY - startY;

                    if (velocityY < -0.5 || dy < -25) {
                        closeAnimation();
                        return;
                    }

                    Animated.parallel([
                        Animated.timing(opacityAnim, {
                            duration: openAnimationDelay,
                            easing: Easing.linear,
                            useNativeDriver: true,
                            toValue: 1
                        }),
                        Animated.timing(transformAnim, {
                            duration: openAnimationDelay,
                            easing: Easing.linear,
                            useNativeDriver: true,
                            toValue: 0
                        })
                    ]).start();
                };

                safeGlobal.addEventListener("pointermove", handlePointerMove);
                safeGlobal.addEventListener("pointerup", handlePointerUp);
            } : undefined}
            onLayout={(event) => {
                const _contentHeight = event.nativeEvent.layout.height;

                contentHeight.current = _contentHeight;

                setIsMeasured(true);
            }}
        >
            <TouchableWithoutFeedback
                onPress={() => {
                    if(onPress) onPress({
                        id
                    });

                    if(isCloseOnPress) {
                        closeAnimation();
                    }
                }}
            >
                {children ? children : renderContainer()}
            </TouchableWithoutFeedback>
        </Animated.View>
    </Portal>;
};
export default SnackBar;
