/**
 * Tooltip Component for Tutorial Guidance
 */

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

export interface TooltipProps {
    children: React.ReactElement;
    content: string;
    hint?: string; // Optional hint text (e.g., "Recommended for first-time users")
    position?: 'top' | 'bottom' | 'left' | 'right';
    show: boolean; // Control visibility based on tutorial_watched
    tooltipId: string; // Unique ID for this tooltip
    currentTooltipId: string | null; // ID of currently active tooltip
    onDismiss?: () => void; // Callback when user dismisses/interacts with tooltip
    currentIndex?: number; // Current tooltip index (1-based)
    totalCount?: number; // Total number of tooltips
    onSkip?: () => void; // Callback when user skips tutorial
}

const Tooltip: React.FC<TooltipProps> = ({
    children,
    content,
    hint,
    position = 'top',
    show,
    tooltipId,
    currentTooltipId,
    onDismiss,
    currentIndex,
    totalCount,
    onSkip,
}) => {
    const [isVisible, setIsVisible] = useState(false);
    const [isFadingOut, setIsFadingOut] = useState(false);
    // Only show if this is the current tooltip and tutorial is enabled
    const shouldShow = show && currentTooltipId === tooltipId;
    const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 });
    const triggerRef = useRef<HTMLElement | null>(null);
    const tooltipRef = useRef<HTMLDivElement | null>(null);
    const fadeOutTimeoutRef = useRef<NodeJS.Timeout | null>(null);

    useEffect(() => {
        // Clear any pending fade-out timeout
        if (fadeOutTimeoutRef.current) {
            clearTimeout(fadeOutTimeoutRef.current);
            fadeOutTimeoutRef.current = null;
        }

        if (shouldShow && triggerRef.current) {
            // If we were fading out, cancel it
            setIsFadingOut(false);
            // Small delay before showing to allow previous tooltip to fade out
            const showTimeout = setTimeout(() => {
                setIsVisible(true);
                setIsFadingOut(false);
                // Use setTimeout to ensure DOM is updated before calculating position
                setTimeout(() => {
                    updatePosition();
                }, 0);
            }, 200); // 200ms delay to allow fade-out animation

            return () => clearTimeout(showTimeout);
        } else if (isVisible && !shouldShow) {
            // Start fade-out animation
            setIsFadingOut(true);
            // Hide after fade-out animation completes
            fadeOutTimeoutRef.current = setTimeout(() => {
                setIsVisible(false);
                setIsFadingOut(false);
            }, 200); // Match CSS animation duration

            return () => {
                if (fadeOutTimeoutRef.current) {
                    clearTimeout(fadeOutTimeoutRef.current);
                }
            };
        } else if (!shouldShow && !isVisible) {
            // Ensure state is clean when not showing
            setIsFadingOut(false);
        }
    }, [shouldShow]);

    useEffect(() => {
        if (isVisible && tooltipRef.current) {
            // Update position after tooltip is rendered
            const updatePos = () => {
                requestAnimationFrame(() => {
                    updatePosition();
                });
            };
            updatePos();
            const handleResize = () => updatePos();
            const handleScroll = () => updatePos();
            window.addEventListener('resize', handleResize);
            window.addEventListener('scroll', handleScroll, true);
            return () => {
                window.removeEventListener('resize', handleResize);
                window.removeEventListener('scroll', handleScroll, true);
            };
        }
    }, [isVisible]);

    const updatePosition = () => {
        if (!triggerRef.current || !tooltipRef.current) return;

        const triggerRect = triggerRef.current.getBoundingClientRect();
        const tooltipRect = tooltipRef.current.getBoundingClientRect();
        const arrowSize = 9; // Arrow size in pixels
        const gap = 8; // Gap between trigger and tooltip

        let top = 0;
        let left = 0;

        switch (position) {
            case 'top':
                // Position above the trigger, accounting for arrow
                top = triggerRect.top - tooltipRect.height - gap;
                left =
                    triggerRect.left +
                    triggerRect.width / 2 -
                    tooltipRect.width / 2;
                break;
            case 'bottom':
                // Position below the trigger, accounting for arrow
                top = triggerRect.bottom + gap;
                left =
                    triggerRect.left +
                    triggerRect.width / 2 -
                    tooltipRect.width / 2;
                break;
            case 'left':
                // Position to the left of the trigger, accounting for arrow
                top =
                    triggerRect.top +
                    triggerRect.height / 2 -
                    tooltipRect.height / 2;
                left = triggerRect.left - tooltipRect.width - gap;
                break;
            case 'right':
                // Position to the right of the trigger, accounting for arrow
                top =
                    triggerRect.top +
                    triggerRect.height / 2 -
                    tooltipRect.height / 2;
                left = triggerRect.right + gap;
                break;
        }

        // Keep tooltip within viewport (using viewport coordinates since tooltip is fixed)
        const padding = 8;
        if (left < padding) left = padding;
        if (left + tooltipRect.width > window.innerWidth - padding) {
            left = window.innerWidth - tooltipRect.width - padding;
        }
        if (top < padding) {
            top = padding;
        }
        if (top + tooltipRect.height > window.innerHeight - padding) {
            top = window.innerHeight - tooltipRect.height - padding;
        }

        setTooltipPosition({ top, left });
    };

    const handleDismiss = () => {
        setIsVisible(false);
        if (onDismiss) {
            onDismiss();
        }
    };

    // Always render children, but only show tooltip if it's the current one
    if (!show) {
        return children;
    }

    const clonedChild = React.cloneElement(children, {
        ref: (node: HTMLElement | null) => {
            triggerRef.current = node;
            // Preserve original ref if it exists (function refs only)
            const originalRef = (children as any).ref;
            if (typeof originalRef === 'function') {
                originalRef(node);
            }
            // Note: Object refs (React.MutableRefObject) are not preserved
            // as they may be read-only. This is acceptable since we're wrapping the element.
        },
    });

    return (
        <>
            {clonedChild}
            {isVisible && (
                <>
                    {/* Backdrop */}
                    <div
                        className={`fixed inset-0 z-[9998] bg-black bg-opacity-20 ${
                            isFadingOut ? 'animate-fade-out' : 'animate-fade-in'
                        }`}
                        onClick={handleDismiss}
                        style={{ pointerEvents: 'auto' }}
                    />
                    {/* Tooltip */}
                    <div
                        ref={tooltipRef}
                        className={`fixed z-[9999] bg-white border border-gray-300 rounded-lg shadow-xl p-4 max-w-sm tooltip-arrow-${position} ${
                            isFadingOut ? 'animate-fade-out' : 'animate-fade-in'
                        }`}
                        style={{
                            top: `${tooltipPosition.top}px`,
                            left: `${tooltipPosition.left}px`,
                            pointerEvents: 'auto',
                        }}
                        role="tooltip"
                    >
                        <div className="relative">
                            {currentIndex !== undefined &&
                                totalCount !== undefined && (
                                    <div className="text-xs text-gray-500 mb-2 text-right">
                                        {currentIndex} of {totalCount}
                                    </div>
                                )}
                            <p className="text-sm text-gray-800 mb-2">
                                {content}
                            </p>
                            {hint && (
                                <p className="text-xs text-gray-600 italic mb-3">
                                    {hint}
                                </p>
                            )}
                            <div className="flex gap-2">
                                {onSkip && (
                                    <button
                                        onClick={onSkip}
                                        className="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 text-xs font-medium py-2 px-3 rounded transition-colors"
                                    >
                                        Skip
                                    </button>
                                )}
                                <button
                                    onClick={handleDismiss}
                                    className={`${onSkip ? 'flex-1' : 'w-full'} bg-[#080081] hover:bg-[#060066] text-white text-xs font-medium py-2 px-3 rounded transition-colors`}
                                >
                                    Got it
                                </button>
                            </div>
                        </div>
                    </div>
                </>
            )}
        </>
    );
};

export default Tooltip;
