import {
    useEffect,
    useState,
    type FC,
    useRef
} from "react";
import {
    useWindowDimensions,
    type ViewStyle,
    Pressable,
    Animated,
    Platform,
    Easing,
    View
} from "react-native";
import type ITooltipProps from "./type";
import stylesheet, {
    getTooltipType,
    useStyles
} from "./stylesheet";
import {
    NCoreUIKitTheme
} from "../../core/hooks";
import {
    X as XIcon
} from "lucide-react-native";
import Button from "../button";
import Text from "../text";

const Tooltip: FC<ITooltipProps> = ({
    isCloseOnPressActionButton = true,
    location = {
        horizontal: "center",
        vertical: "top"
    },
    isCloseOnPress = false,
    contentContainerStyle,
    triggerMode = "hover",
    sizing = "content",
    icon: CustomIcon,
    type = "neutral",
    containerStyle,
    customTheme,
    caretStyle,
    isVisible,
    children,
    onClosed,
    subTitle,
    content,
    onClose,
    action,
    height,
    onOpen,
    style,
    title,
    width
}) => {
    const {
        radiuses,
        colors,
        spaces
    } = NCoreUIKitTheme.useContext(customTheme);

    const [
        wrapperSize,
        setWrapperSize
    ] = useState({
        height: 0,
        width: 0
    });

    const [
        tooltipSize,
        setTooltipSize
    ] = useState({
        height: 0,
        width: 0
    });

    const [
        isInternalVisible,
        setIsInternalVisible
    ] = useState(false);

    const {
        width: windowWidth
    } = useWindowDimensions();

    const opacityAnim = useRef(new Animated.Value(0)).current;
    const wrapperRef = useRef<View>(null);
    const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);

    const handleHoverIn = () => {
        if (hoverTimeoutRef.current) {
            clearTimeout(hoverTimeoutRef.current);
            hoverTimeoutRef.current = null;
        }
        if (isVisible === undefined) {
            setIsInternalVisible(true);
        }
        if (onOpen) onOpen();
    };

    const handleHoverOut = () => {
        hoverTimeoutRef.current = setTimeout(() => {
            if (isVisible === undefined) {
                setIsInternalVisible(false);
            }
            if (onClose) onClose();
            hoverTimeoutRef.current = null;
        }, 100);
    };

    const currentType = getTooltipType({
        type
    });

    const {
        contentContainer: contentContainerDynamicStyle,
        containerObject: containerObjectDynamicStyle,
        iconContainer: iconContainerDynamicStyle,
        container: containerDynamicStyle,
        subTitle: subTitleDynamicStyle,
        action: actionDynamicStyle,
        title: titleDynamicStyle,
        caret: caretDynamicStyle
    } = useStyles({
        currentType,
        radiuses,
        colors,
        spaces,
        height,
        sizing,
        width,
        type
    });

    const isShow = isVisible !== undefined ? isVisible : isInternalVisible;

    useEffect(() => {
        if(isShow) {
            if(onOpen) onOpen();

            Animated.timing(opacityAnim, {
                useNativeDriver: Platform.OS !== "web",
                easing: Easing.bezier(0, 0, 0, 1),
                duration: 250,
                toValue: 1
            }).start();
        } else {
            Animated.timing(opacityAnim, {
                useNativeDriver: Platform.OS !== "web",
                easing: Easing.bezier(0, 0, 0, 1),
                duration: 250,
                toValue: 0
            }).start(({
                finished
            }) => {
                if(finished && onClosed) {
                    onClosed();
                }
            });
        }
    }, [
        isShow
    ]);

    useEffect(() => {
        if (Platform.OS === "web" && triggerMode === "click" && isShow) {
            const handleClickOutside = (event: Event) => {
                const target = event.target as Node;
                const node = wrapperRef.current as unknown as HTMLElement;

                if (node && node.contains && !node.contains(target)) {
                    if (isVisible === undefined) {
                        setIsInternalVisible(false);
                    }

                    if (onClose) onClose();
                }
            };

            document.addEventListener("mousedown", handleClickOutside);

            return () => {
                document.removeEventListener("mousedown", handleClickOutside);
            };
        }

        return undefined;
    }, [
        isShow,
        triggerMode,
        isVisible,
        onClose
    ]);

    const handleClose = () => {
        if(isVisible === undefined) {
            setIsInternalVisible(false);
        }
        if(onClose) onClose();
    };

    const handleToggle = () => {
        if(isVisible === undefined) {
            setIsInternalVisible(!isInternalVisible);
        }

        if(!isShow && onOpen) {
            onOpen();
        } else if (isShow && onClose) {
            onClose();
        }
    };

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

        return <View
            style={[
                stylesheet.iconContainer,
                iconContainerDynamicStyle
            ]}
        >
            <CustomIcon
                color={currentType.iconColor}
                size={16}
            />
        </View>;
    };

    const renderContent = () => {
        if(content) {
            if(typeof content === "function") {
                return content();
            }

            return content;
        }

        return <View
            style={[
                stylesheet.contentContainer,
                contentContainerDynamicStyle,
                contentContainerStyle
            ]}
        >
            {
                title ?
                    <Text
                        color={currentType.titleColor}
                        variant="labelMediumSize"
                        style={{
                            ...stylesheet.title,
                            ...titleDynamicStyle
                        }}
                        numberOfLines={3}
                    >
                        {title}
                    </Text>
                :
                    null
            }
            {
                subTitle ?
                    <Text
                        color={currentType.subTitleColor}
                        style={{
                            ...stylesheet.subTitle,
                            ...subTitleDynamicStyle
                        }}
                        variant="labelSmallSize"
                        numberOfLines={2}
                    >
                        {subTitle}
                    </Text>
                :
                    null
            }
        </View>;
    };

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

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

                return <XIcon
                    color={colors.content.text[currentType.actionColor]}
                    size={16}
                />;
            }}
            onPress={() => {
                if(isCloseOnPressActionButton) handleClose();

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

    const getTooltipStyle = (): ViewStyle => {
        const _style: ViewStyle = {};

        if(tooltipSize.width > 0 && wrapperSize.width > 0) {
            if(location.vertical === "top") {
                _style.bottom = wrapperSize.height + 8;
            } else if (location.vertical === "bottom") {
                _style.top = wrapperSize.height + 8;
            } else {
                _style.top = (wrapperSize.height - tooltipSize.height) / 2;
            }

            if(location.horizontal === "left") {
                _style.right = wrapperSize.width + 8;
            } else if (location.horizontal === "right") {
                _style.left = wrapperSize.width + 8;
            } else {
                _style.left = (wrapperSize.width - tooltipSize.width) / 2;
            }
        } else {
            _style.opacity = 0;
        }

        return _style;
    };

    const getCaretStyle = (): ViewStyle => {
        const _style: ViewStyle = {};

        if(location.vertical === "top") {
            _style.bottom = -4;
        } else if (location.vertical === "bottom") {
            _style.top = -4;
        } else {
            _style.top = (tooltipSize.height - 12) / 2;
        }

        if(location.horizontal === "left") {
            _style.right = -4;
        } else if (location.horizontal === "right") {
            _style.left = -4;
        } else {
            _style.left = (tooltipSize.width - 12) / 2;
        }

        if (location.vertical === "top" && location.horizontal === "right") {
            _style.left = 12;
        } else if (location.vertical === "top" && location.horizontal === "left") {
            _style.right = 12;
        } else if (location.vertical === "bottom" && location.horizontal === "right") {
            _style.left = 12;
        } else if (location.vertical === "bottom" && location.horizontal === "left") {
            _style.right = 12;
        }

        return _style;
    };

    const isFixed = sizing === "fixed";

    return <View
        onLayout={(e) => {
            const {
                height,
                width
            } = e.nativeEvent.layout;

            setWrapperSize(prev => {
                if (prev.height === height && prev.width === width) {
                    return prev;
                }
                return {
                    height,
                    width
                };
            });
        }}
        style={[
            stylesheet.wrapper,
            style
        ]}
        ref={wrapperRef}
    >
        <Pressable
            onPointerLeave={triggerMode === "hover" ? handleHoverOut : undefined}
            onPointerEnter={triggerMode === "hover" ? handleHoverIn : undefined}
            onPress={() => {
                if(!isCloseOnPress) {
                    handleToggle();
                } else if(isShow) {
                    handleClose();
                } else {
                    handleToggle();
                }
            }}
        >
            <View>
                {children}
            </View>
        </Pressable>
        {
            isShow || opacityAnim !== undefined ?
                <Animated.View
                    style={[
                        stylesheet.container,
                        containerDynamicStyle,
                        getTooltipStyle(),
                        {
                            maxWidth: isFixed ? undefined : windowWidth - (spaces.spacingMd * 2),
                            opacity: opacityAnim
                        },
                        containerStyle
                    ]}
                    onLayout={(e) => {
                        const {
                            height,
                            width
                        } = e.nativeEvent.layout;

                        setTooltipSize(prev => {
                            if (prev.height === height && prev.width === width) {
                                return prev;
                            }
                            return {
                                height,
                                width
                            };
                        });
                    }}
                    pointerEvents={isShow ? "auto" : "none"}
                >
                    <View
                        onPointerLeave={triggerMode === "hover" ? handleHoverOut : undefined}
                        onPointerEnter={triggerMode === "hover" ? handleHoverIn : undefined}
                        style={stylesheet.hoverWrapper}
                    >
                        <View
                            style={[
                                stylesheet.caret,
                                caretDynamicStyle,
                                getCaretStyle(),
                                caretStyle
                            ]}
                        />
                        <View
                            style={[
                                stylesheet.containerObject,
                                containerObjectDynamicStyle
                            ]}
                        >
                            {renderIcon()}
                            {renderContent()}
                            {renderAction()}
                        </View>
                    </View>
                </Animated.View>
            :
                null
        }
    </View>;
};
export default Tooltip;
