import { useState, useEffect, useRef, useCallback } from 'react';
import { cn } from '@/lib/utils';

export interface TooltipProps {
  content: React.ReactNode;
  children: React.ReactNode;
  position?: 'top' | 'bottom' | 'left' | 'right';
  trigger?: 'hover' | 'click' | 'focus';
  delay?: number;
  showArrow?: boolean;
  maxWidth?: number;
  disabled?: boolean;
  className?: string;
}

/**
 * Composant Tooltip avancé avec positionnement, contenu riche, et triggers multiples.
 */
export function Tooltip({
  content,
  children,
  position = 'top',
  trigger = 'hover',
  delay = 200,
  showArrow = true,
  maxWidth = 300,
  disabled = false,
  className,
}: TooltipProps) {
  const [visible, setVisible] = useState(false);
  const [isMounted, setIsMounted] = useState(false);
  const [calculatedPosition, setCalculatedPosition] = useState(position);
  const [tooltipStyle, setTooltipStyle] = useState<React.CSSProperties>({});
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);
  const hideTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const wrapperRef = useRef<HTMLDivElement>(null);
  const tooltipRef = useRef<HTMLDivElement>(null);

  // Calcul du positionnement avec flip et shift
  const calculatePosition = useCallback(() => {
    if (!wrapperRef.current || !tooltipRef.current || !visible) return;

    const wrapperRect = wrapperRef.current.getBoundingClientRect();
    const tooltipRect = tooltipRef.current.getBoundingClientRect();
    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;
    const margin = 8;

    let newPosition = position;
    let offsetX = 0;
    let offsetY = 0;

    // Flip: inverser la position si le tooltip sort de l'écran
    switch (position) {
      case 'top':
        if (wrapperRect.top - tooltipRect.height - margin < 0) {
          newPosition = 'bottom';
        }
        break;
      case 'bottom':
        if (wrapperRect.bottom + tooltipRect.height + margin > viewportHeight) {
          newPosition = 'top';
        }
        break;
      case 'left':
        if (wrapperRect.left - tooltipRect.width - margin < 0) {
          newPosition = 'right';
        }
        break;
      case 'right':
        if (wrapperRect.right + tooltipRect.width + margin > viewportWidth) {
          newPosition = 'left';
        }
        break;
    }

    // Shift: ajuster la position pour rester dans la viewport
    if (newPosition === 'top' || newPosition === 'bottom') {
      const centerX = wrapperRect.left + wrapperRect.width / 2;
      const tooltipHalfWidth = tooltipRect.width / 2;

      if (centerX - tooltipHalfWidth < margin) {
        offsetX = margin - (centerX - tooltipHalfWidth);
      } else if (centerX + tooltipHalfWidth > viewportWidth - margin) {
        offsetX = viewportWidth - margin - (centerX + tooltipHalfWidth);
      }
    } else {
      const centerY = wrapperRect.top + wrapperRect.height / 2;
      const tooltipHalfHeight = tooltipRect.height / 2;

      if (centerY - tooltipHalfHeight < margin) {
        offsetY = margin - (centerY - tooltipHalfHeight);
      } else if (centerY + tooltipHalfHeight > viewportHeight - margin) {
        offsetY = viewportHeight - margin - (centerY + tooltipHalfHeight);
      }
    }

    setCalculatedPosition(newPosition);
    setTooltipStyle({
      ...(offsetX !== 0 && { transform: `translateX(${offsetX}px)` }),
      ...(offsetY !== 0 && { transform: `translateY(${offsetY}px)` }),
    });
  }, [position, visible]);

  useEffect(() => {
    if (visible && isMounted) {
      // Recalculer après le rendu
      setTimeout(() => {
        calculatePosition();
      }, 0);

      // Recalculer lors du scroll et resize
      const handleRecalculate = () => calculatePosition();
      window.addEventListener('scroll', handleRecalculate, true);
      window.addEventListener('resize', handleRecalculate);

      return () => {
        window.removeEventListener('scroll', handleRecalculate, true);
        window.removeEventListener('resize', handleRecalculate);
      };
    }
    return undefined;
  }, [visible, isMounted, calculatePosition]);

  const showTooltip = useCallback(() => {
    if (disabled) return;

    if (hideTimeoutRef.current) {
      clearTimeout(hideTimeoutRef.current);
      hideTimeoutRef.current = null;
    }

    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }

    if (delay > 0) {
      timeoutRef.current = setTimeout(() => {
        setIsMounted(true);
        setTimeout(() => setVisible(true), 0);
      }, delay);
    } else {
      setIsMounted(true);
      setTimeout(() => setVisible(true), 0);
    }
  }, [delay, disabled]);

  const hideTooltip = useCallback(() => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
      timeoutRef.current = null;
    }

    setVisible(false);
    hideTimeoutRef.current = setTimeout(() => {
      setIsMounted(false);
      hideTimeoutRef.current = null;
    }, 200);
  }, []);

  // Gestion du trigger click
  const handleClick = useCallback(() => {
    if (trigger === 'click') {
      if (visible) {
        hideTooltip();
      } else {
        showTooltip();
      }
    }
  }, [trigger, visible, showTooltip, hideTooltip]);

  // Fermer au clic en dehors pour le trigger click
  useEffect(() => {
    if (trigger === 'click' && visible) {
      const handleClickOutside = (event: MouseEvent) => {
        if (
          wrapperRef.current &&
          !wrapperRef.current.contains(event.target as Node) &&
          tooltipRef.current &&
          !tooltipRef.current.contains(event.target as Node)
        ) {
          hideTooltip();
        }
      };

      document.addEventListener('mousedown', handleClickOutside);
      return () => {
        document.removeEventListener('mousedown', handleClickOutside);
      };
    }
    return undefined;
  }, [trigger, visible, hideTooltip]);

  const triggerProps = {
    hover: {
      onMouseEnter: showTooltip,
      onMouseLeave: hideTooltip,
    },
    click: {
      onClick: handleClick,
    },
    focus: {
      onFocus: showTooltip,
      onBlur: hideTooltip,
    },
  }[trigger];

  const positionClasses = {
    top: 'bottom-full left-1/2 -translate-x-1/2 mb-2',
    bottom: 'top-full left-1/2 -translate-x-1/2 mt-2',
    left: 'right-full top-1/2 -translate-y-1/2 mr-2',
    right: 'left-full top-1/2 -translate-y-1/2 ml-2',
  };

  const arrowClasses = {
    top: 'top-full left-1/2 -translate-x-1/2 border-t-popover border-l-transparent border-r-transparent border-b-transparent',
    bottom:
      'bottom-full left-1/2 -translate-x-1/2 border-b-popover border-l-transparent border-r-transparent border-t-transparent',
    left: 'left-full top-1/2 -translate-y-1/2 border-l-popover border-t-transparent border-b-transparent border-r-transparent',
    right:
      'right-full top-1/2 -translate-y-1/2 border-r-popover border-t-transparent border-b-transparent border-l-transparent',
  };

  useEffect(() => {
    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
      if (hideTimeoutRef.current) {
        clearTimeout(hideTimeoutRef.current);
      }
    };
  }, []);

  if (disabled) {
    return <>{children}</>;
  }

  const tooltipContent = (
    <>
      {isMounted && (
        <div
          ref={tooltipRef}
          className={cn(
            'absolute z-50 px-3 py-1.5 text-sm text-popover-foreground bg-popover rounded-md shadow-md',
            'border border-border pointer-events-none',
            'transition-all duration-200',
            positionClasses[calculatedPosition],
            visible ? 'opacity-100 scale-100' : 'opacity-0 scale-95',
            className,
          )}
          role="tooltip"
          style={{ maxWidth: `${maxWidth}px`, ...tooltipStyle }}
        >
          {content}
          {showArrow && (
            <div
              className={cn(
                'absolute w-0 h-0 border-4',
                arrowClasses[calculatedPosition],
              )}
            />
          )}
        </div>
      )}
    </>
  );

  return (
    <div ref={wrapperRef} className="relative inline-block" {...triggerProps}>
      {children}
      {tooltipContent}
    </div>
  );
}
