import { useState, useRef, useEffect, useCallback } from 'react';

// Optimized animation frame throttle for smooth movement
function rafThrottle(func) {
    let rafId = null;
    let latestArgs = null;
    const throttledFn = (...args) => {
        latestArgs = args;
        if (rafId === null) {
            rafId = requestAnimationFrame(() => {
                if (latestArgs) {
                    func(...latestArgs);
                }
                rafId = null;
                latestArgs = null;
            });
        }
    };
    // Add cleanup method
    throttledFn.cancel = () => {
        if (rafId !== null) {
            cancelAnimationFrame(rafId);
            rafId = null;
            latestArgs = null;
        }
    };
    return throttledFn;
}
function useTooltipPosition({ containerRef, padding = 10, offset = 15, isMobile = false, animation = {
    duration: 0.08,
    ease: "easeOut",
    enabled: true,
}, }) {
    const [tooltipData, setTooltipData] = useState(null);
    const tooltipRef = useRef(null);
    const isUnmountedRef = useRef(false);
    // Track component mount status to prevent state updates after unmount
    useEffect(() => {
        isUnmountedRef.current = false;
        return () => {
            isUnmountedRef.current = true;
        };
    }, []);
    /**
     * Safe state setter that checks if component is still mounted
     * Supports both direct values and function updates like React.setState
     */
    const safeSetTooltipData = useCallback((data) => {
        if (!isUnmountedRef.current) {
            setTooltipData(prevData => {
                if (typeof data === 'function') {
                    return data(prevData);
                }
                return data;
            });
        }
    }, []);
    /**
     * Calculate bounded position within container with simplified logic
     */
    const calculateBoundedPosition = useCallback((x, y, tooltipWidth = 0, tooltipHeight = 0) => {
        if (!containerRef.current)
            return { x, y };
        try {
            const containerRect = containerRef.current.getBoundingClientRect();
            const viewportWidth = window.innerWidth;
            const viewportHeight = window.innerHeight;
            let boundedX = x;
            let boundedY = y;
            // Simple X positioning: try right, then left, then clamp
            if (boundedX + tooltipWidth + padding > Math.min(containerRect.right, viewportWidth)) {
                // Try positioning to the left of cursor
                boundedX = x - tooltipWidth - offset;
            }
            // Ensure it doesn't go off the left edge
            boundedX = Math.max(Math.max(containerRect.left, 0) + padding, boundedX);
            // Final clamp to viewport
            boundedX = Math.min(boundedX, viewportWidth - tooltipWidth - padding);
            // Simple Y positioning: try below, then above, then clamp
            if (boundedY + tooltipHeight + padding > Math.min(containerRect.bottom, viewportHeight)) {
                // Try positioning above cursor
                boundedY = y - tooltipHeight - offset;
            }
            // Ensure it doesn't go off the top edge
            boundedY = Math.max(Math.max(containerRect.top, 0) + padding, boundedY);
            // Final clamp to viewport
            boundedY = Math.min(boundedY, viewportHeight - tooltipHeight - padding);
            return { x: boundedX, y: boundedY };
        }
        catch (error) {
            if (process.env.NODE_ENV !== 'production') {
                console.warn('[useTooltipPosition]: Error calculating tooltip position:', error);
            }
            return { x, y };
        }
    }, [containerRef, padding, offset]);
    /**
     * Get tooltip position for mouse events with stable positioning
     */
    const getMouseTooltipPosition = useCallback((event) => {
        var _a, _b;
        // Use page coordinates to avoid scroll issues
        const x = event.clientX;
        const y = event.clientY - offset;
        // Get current tooltip dimensions or use estimated defaults
        const tooltipWidth = ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 200; // reasonable default
        const tooltipHeight = ((_b = tooltipRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60; // reasonable default
        return calculateBoundedPosition(x, y, tooltipWidth, tooltipHeight);
    }, [calculateBoundedPosition, offset]);
    /**
     * Get tooltip position for SVG elements (mobile/touch)
     */
    const getSVGTooltipPosition = useCallback((event, svgX, svgY, actualDimensions) => {
        var _a, _b;
        try {
            const svgElement = event.currentTarget.closest('svg');
            const svgRect = svgElement === null || svgElement === void 0 ? void 0 : svgElement.getBoundingClientRect();
            if (!svgRect || !actualDimensions.width || !actualDimensions.height) {
                if (process.env.NODE_ENV !== 'production') {
                    console.warn('[useTooltipPosition]: SVG positioning fallback: missing SVG rect or dimensions');
                }
                return getMouseTooltipPosition(event);
            }
            // Calculate scale factors using actual dimensions
            const scaleX = svgRect.width / actualDimensions.width;
            const scaleY = svgRect.height / actualDimensions.height;
            // Convert SVG coordinates to screen coordinates
            const screenX = svgRect.left + svgX * scaleX;
            const screenY = svgRect.top + svgY * scaleY;
            const x = screenX;
            const y = screenY - offset;
            const tooltipWidth = ((_a = tooltipRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 200;
            const tooltipHeight = ((_b = tooltipRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
            return calculateBoundedPosition(x, y, tooltipWidth, tooltipHeight);
        }
        catch (error) {
            if (process.env.NODE_ENV !== 'production') {
                console.warn('[useTooltipPosition]: Error in SVG tooltip positioning:', error);
            }
            return getMouseTooltipPosition(event);
        }
    }, [calculateBoundedPosition, getMouseTooltipPosition, offset]);
    /**
     * Show tooltip with content and position
     */
    const showTooltip = useCallback((content, position) => {
        safeSetTooltipData({
            x: position.x,
            y: position.y,
            content,
        });
    }, [safeSetTooltipData]);
    /**
     * Update tooltip position (for mouse move events)
     */
    const updateTooltipPosition = useCallback((position) => {
        safeSetTooltipData(prev => prev ? { ...prev, x: position.x, y: position.y } : null);
    }, [safeSetTooltipData]);
    // Create RAF-throttled version of updateTooltipPosition for smooth movement
    const rafThrottledUpdateRef = useRef(null);
    const rafThrottledUpdate = useCallback((position) => {
        if (!isUnmountedRef.current) {
            updateTooltipPosition(position);
        }
    }, [updateTooltipPosition]);
    // Initialize RAF throttling
    useEffect(() => {
        rafThrottledUpdateRef.current = rafThrottle(rafThrottledUpdate);
        return () => {
            var _a;
            if ((_a = rafThrottledUpdateRef.current) === null || _a === void 0 ? void 0 : _a.cancel) {
                rafThrottledUpdateRef.current.cancel();
            }
        };
    }, [rafThrottledUpdate]);
    /**
     * Hide tooltip and cancel any pending updates
     */
    const hideTooltip = useCallback(() => {
        var _a;
        // Cancel any pending RAF updates
        if ((_a = rafThrottledUpdateRef.current) === null || _a === void 0 ? void 0 : _a.cancel) {
            rafThrottledUpdateRef.current.cancel();
        }
        safeSetTooltipData(null);
    }, [safeSetTooltipData]);
    /**
     * Handle mouse enter for chart elements
     */
    const handleMouseEnter = useCallback((event, content, svgCoordinates) => {
        try {
            let position;
            if (isMobile && svgCoordinates) {
                position = getSVGTooltipPosition(event, svgCoordinates.x, svgCoordinates.y, svgCoordinates.dimensions);
            }
            else {
                position = getMouseTooltipPosition(event);
            }
            showTooltip(content, position);
        }
        catch (error) {
            if (process.env.NODE_ENV !== 'production') {
                console.warn('[useTooltipPosition]: Error handling mouse enter:', error);
            }
        }
    }, [isMobile, getSVGTooltipPosition, getMouseTooltipPosition, showTooltip]);
    /**
     * Handle mouse move with optimized RAF throttling for smooth movement
     */
    const handleMouseMove = useCallback((event, svgCoordinates) => {
        if (!tooltipData)
            return;
        try {
            // Always use mouse position for consistent movement
            const position = getMouseTooltipPosition(event);
            if (rafThrottledUpdateRef.current) {
                rafThrottledUpdateRef.current(position);
            }
            else {
                // Fallback to direct update
                updateTooltipPosition(position);
            }
        }
        catch (error) {
            if (process.env.NODE_ENV !== 'production') {
                console.warn('[useTooltipPosition]: Error handling mouse move:', error);
            }
        }
    }, [tooltipData, getMouseTooltipPosition, updateTooltipPosition]);
    /**
     * Handle mouse leave for chart elements
     */
    const handleMouseLeave = useCallback(() => {
        hideTooltip();
    }, [hideTooltip]);
    // Update tooltip position when container resizes (simplified)
    useEffect(() => {
        if (!tooltipData || !containerRef.current)
            return;
        const handleResize = () => {
            if (tooltipData && tooltipRef.current && !isUnmountedRef.current) {
                try {
                    const tooltipWidth = tooltipRef.current.offsetWidth;
                    const tooltipHeight = tooltipRef.current.offsetHeight;
                    const newPosition = calculateBoundedPosition(tooltipData.x, tooltipData.y, tooltipWidth, tooltipHeight);
                    // Use direct update for resize, not RAF throttled
                    updateTooltipPosition(newPosition);
                }
                catch (error) {
                    if (process.env.NODE_ENV !== 'production') {
                        console.warn('[useTooltipPosition]: Error updating tooltip position on resize:', error);
                    }
                }
            }
        };
        // Use window resize instead of ResizeObserver for better performance
        window.addEventListener('resize', handleResize);
        return () => {
            window.removeEventListener('resize', handleResize);
        };
    }, [tooltipData, containerRef, calculateBoundedPosition, updateTooltipPosition]);
    return {
        tooltipData,
        tooltipRef,
        showTooltip,
        hideTooltip,
        updateTooltipPosition,
        handleMouseEnter,
        handleMouseMove,
        handleMouseLeave,
        getMouseTooltipPosition,
        getSVGTooltipPosition,
        // Animation configuration for the consuming component
        animationConfig: {
            animate: tooltipData ? { x: tooltipData.x, y: tooltipData.y, opacity: 1 } : { opacity: 0 },
            transition: animation.enabled ? {
                duration: animation.duration,
                ease: animation.ease,
                // Reduce layout thrashing by using transform instead of changing x/y directly
                type: "tween",
            } : { duration: 0 },
            initial: { opacity: 0 },
            style: tooltipData ? {
                position: 'fixed',
                left: 0,
                top: 0,
                transform: `translate(${tooltipData.x}px, ${tooltipData.y}px)`,
                willChange: 'transform, opacity', // Optimize for animations
            } : {},
        },
    };
}

export { useTooltipPosition };
