/**
 * Tooltip.tsx
 * 
 * A simple tooltip component that renders via portal to escape overflow:hidden containers.
 * Used for method toggle buttons (PCA/UMAP/t-SNE) in EmbeddingProjector and other components.
 * 
 * @package @glam/ui
 */

import React, { useState, useRef, useEffect, useCallback } from 'react';
import { createPortal } from 'react-dom';
import '../styles/Tooltip.css';

interface TooltipProps {
  content: string;
  children: React.ReactNode;
  position?: 'top' | 'bottom' | 'left' | 'right';
  delay?: number;
  maxWidth?: number;
}

export const Tooltip: React.FC<TooltipProps> = ({
  content,
  children,
  position = 'bottom',
  delay = 300,
  maxWidth = 300,
}) => {
  const [isVisible, setIsVisible] = useState(false);
  const [coords, setCoords] = useState<{ x: number; y: number } | null>(null);
  const triggerRef = useRef<HTMLSpanElement>(null);
  const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const isHoveringRef = useRef(false);

  const calculatePosition = useCallback(() => {
    if (!triggerRef.current) return null;
    
    const rect = triggerRef.current.getBoundingClientRect();
    
    let x = 0;
    let y = 0;
    
    switch (position) {
      case 'top':
        x = rect.left + rect.width / 2;
        y = rect.top - 8;
        break;
      case 'bottom':
        x = rect.left + rect.width / 2;
        y = rect.bottom + 8;
        break;
      case 'left':
        x = rect.left - 8;
        y = rect.top + rect.height / 2;
        break;
      case 'right':
        x = rect.right + 8;
        y = rect.top + rect.height / 2;
        break;
    }
    
    return { x, y };
  }, [position]);

  const showTooltip = useCallback(() => {
    if (!isHoveringRef.current) return;
    
    const newCoords = calculatePosition();
    if (newCoords) {
      setCoords(newCoords);
      setIsVisible(true);
    }
  }, [calculatePosition]);

  const handleMouseEnter = useCallback(() => {
    isHoveringRef.current = true;
    
    // Clear any existing timeout
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }
    
    // Calculate position immediately but delay visibility
    timeoutRef.current = setTimeout(showTooltip, delay);
  }, [delay, showTooltip]);

  const handleMouseLeave = useCallback(() => {
    isHoveringRef.current = false;
    
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
      timeoutRef.current = null;
    }
    
    setIsVisible(false);
    setCoords(null);
  }, []);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
      }
    };
  }, []);

  // Recalculate position on scroll/resize while visible
  useEffect(() => {
    if (!isVisible) return;
    
    const handleReposition = () => {
      const newCoords = calculatePosition();
      if (newCoords) {
        setCoords(newCoords);
      }
    };
    
    window.addEventListener('scroll', handleReposition, true);
    window.addEventListener('resize', handleReposition);
    
    return () => {
      window.removeEventListener('scroll', handleReposition, true);
      window.removeEventListener('resize', handleReposition);
    };
  }, [isVisible, calculatePosition]);

  // Don't render tooltip if no coords yet
  const tooltipElement = isVisible && content && coords ? (
    <div
      className={`ui-tooltip ui-tooltip--${position}`}
      style={{
        left: coords.x,
        top: coords.y,
        maxWidth: maxWidth,
      }}
      role="tooltip"
      aria-hidden={!isVisible}
    >
      <div className="ui-tooltip__content">{content}</div>
      <div className="ui-tooltip__arrow" />
    </div>
  ) : null;

  return (
    <>
      <span
        ref={triggerRef}
        className="ui-tooltip-trigger"
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        onFocus={handleMouseEnter}
        onBlur={handleMouseLeave}
      >
        {children}
      </span>
      {tooltipElement && createPortal(tooltipElement, document.body)}
    </>
  );
};

export default Tooltip;
