import { useState, useEffect, useRef, ReactNode } from 'react';
import { createPortal } from 'react-dom';
import '../../styles/components/TooltipStyles.css';

// 提示框主题
export type TooltipTheme = 'dark' | 'light' | 'primary' | 'success' | 'warning' | 'error' | 'info';

// 提示框位置
export type TooltipPlacement = 'top' | 'bottom' | 'left' | 'right';

// 提示框属性
export interface TooltipProps {
  children: ReactNode;               // 触发元素
  content: ReactNode;                // 提示内容
  theme?: TooltipTheme;              // 主题样式
  placement?: TooltipPlacement;      // 显示位置
  rich?: boolean;                    // 是否为富文本提示
  header?: ReactNode;                // 富文本提示标题
  footer?: ReactNode;                // 富文本提示页脚
  trigger?: 'hover' | 'click';       // 触发方式
  visible?: boolean;                 // 是否显示（受控模式）
  showArrow?: boolean;               // 是否显示箭头
  maxWidth?: number | string;        // 最大宽度
  className?: string;                // 自定义类名
  onVisibleChange?: (visible: boolean) => void; // 显示状态变化回调
  fixedPlacement?: boolean;          // 是否固定显示位置，不自动切换
  maxHeight?: number | string;       // 最大高度，超出将显示滚动条
  scrollable?: boolean;              // 是否可滚动
}

/**
 * Tooltip 组件
 * 
 * 提供增强的悬浮提示功能，支持多种主题、位置和富文本模式
 */
export function Tooltip({
  children,
  content,
  theme = 'dark',
  placement = 'top',
  rich = false,
  header,
  footer,
  trigger = 'hover',
  visible: controlledVisible,
  showArrow = true,
  maxWidth = 320,
  className = '',
  onVisibleChange,
  fixedPlacement = false, // 默认不固定位置
  maxHeight = 300,        // 默认最大高度300px
  scrollable = true       // 默认允许滚动
}: TooltipProps) {
  // 使用内部状态管理提示框显示状态（非受控模式）
  const [visible, setVisible] = useState(false);
  
  // 判断是否为受控组件
  const isControlled = controlledVisible !== undefined;
  
  // 获取实际显示状态
  const isVisible = isControlled ? controlledVisible : visible;
  
  // 引用DOM元素
  const triggerRef = useRef<HTMLDivElement>(null);
  const tooltipRef = useRef<HTMLDivElement>(null);
  const contentRef = useRef<HTMLDivElement>(null);
  
  // 保存当前实际显示位置
  const [actualPlacement, setActualPlacement] = useState<TooltipPlacement>(placement);
  
  // 处理显示状态变化
  const handleVisibleChange = (newVisible: boolean) => {
    if (!isControlled) {
      setVisible(newVisible);
    }
    onVisibleChange?.(newVisible);
    
    // 当显示状态变为false时，重置actualPlacement为初始placement
    if (!newVisible) {
      setActualPlacement(placement);
    }
  };
  
  // 触发器事件处理
  const triggerEvents = trigger === 'hover'
    ? {
        onMouseEnter: () => handleVisibleChange(true),
        onMouseLeave: () => handleVisibleChange(false),
      }
    : {
        onClick: () => handleVisibleChange(!isVisible),
      };
  
  // 更新提示框位置的函数
  const updateTooltipPosition = () => {
    if (!isVisible || !triggerRef.current || !tooltipRef.current) return;
    
    // 获取触发元素位置
    const triggerRect = triggerRef.current.getBoundingClientRect();
    const tooltipRect = tooltipRef.current.getBoundingClientRect();
    
    // 设置最大宽度
    tooltipRef.current.style.maxWidth = typeof maxWidth === 'number' 
      ? `${maxWidth}px` 
      : String(maxWidth);
    
    // 如果内容可滚动，设置最大高度，但仅应用于内容容器而不是整个tooltip
    if (scrollable && contentRef.current) {
      contentRef.current.style.maxHeight = typeof maxHeight === 'number' 
        ? `${maxHeight}px` 
        : String(maxHeight);
      
      // 确保只有内容区域显示滚动条，整个tooltip容器不滚动
      contentRef.current.style.overflowY = 'auto';
      tooltipRef.current.style.overflow = 'visible';
    }
    
    // 计算各个方向的位置
    let top = 0, left = 0;
    let arrowTop = 0, arrowLeft = 0;
    const arrowSize = 8; // 箭头大小
    const gap = 10; // 提示框与触发元素的间距
    
    // 使用actualPlacement而不是placement来计算位置
    let currentPlacement = actualPlacement;
    
    switch (currentPlacement) {
      case 'top':
        left = triggerRect.left + (triggerRect.width / 2) - (tooltipRect.width / 2);
        top = triggerRect.top - tooltipRect.height - arrowSize;
        arrowLeft = tooltipRect.width / 2 - arrowSize;
        arrowTop = tooltipRect.height;
        break;
      case 'bottom':
        left = triggerRect.left + (triggerRect.width / 2) - (tooltipRect.width / 2);
        top = triggerRect.bottom + arrowSize - 8;
        arrowLeft = tooltipRect.width / 2 - arrowSize;
        arrowTop = -arrowSize;
        break;
      case 'left':
        left = triggerRect.left - tooltipRect.width - arrowSize;
        top = triggerRect.top + (triggerRect.height / 2) - (tooltipRect.height / 2);
        arrowLeft = tooltipRect.width;
        arrowTop = tooltipRect.height / 2 - arrowSize;
        break;
      case 'right':
        left = triggerRect.right + arrowSize;
        top = triggerRect.top + (triggerRect.height / 2) - (tooltipRect.height / 2);
        arrowLeft = -arrowSize;
        arrowTop = tooltipRect.height / 2 - arrowSize;
        break;
    }
    
    // 确保提示框不超出视口
    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;
    
    // 调整位置，避免超出视口
    if (left < 0) {
      left = gap;
      arrowLeft = Math.max(triggerRect.left + (triggerRect.width / 2) - left - arrowSize, arrowSize * 2);
    } else if (left + tooltipRect.width > viewportWidth) {
      left = viewportWidth - tooltipRect.width - gap;
      arrowLeft = Math.min(triggerRect.left + (triggerRect.width / 2) - left - arrowSize, tooltipRect.width - arrowSize * 2);
    }
    
    // 如果fixedPlacement为true，则强制使用指定的位置，不自动切换
    if (!fixedPlacement) {
      // 自动调整位置逻辑
      if (top < 0) {
        if (currentPlacement === 'top') {
          // 如果上方放不下，切换到下方
          top = triggerRect.bottom + arrowSize - 8;
          arrowTop = -arrowSize;
          
          // 更新实际位置为bottom
          setActualPlacement('bottom');
          currentPlacement = 'bottom';
          
          // 更新CSS类
          tooltipRef.current.classList.remove('tooltip-top');
          tooltipRef.current.classList.add('tooltip-bottom');
        } else {
          top = gap;
          arrowTop = Math.max(triggerRect.top + (triggerRect.height / 2) - top - arrowSize, arrowSize * 2);
        }
      } else if (top + tooltipRect.height > viewportHeight) {
        if (currentPlacement === 'bottom') {
          // 如果下方放不下，切换到上方
          top = triggerRect.top - tooltipRect.height - arrowSize;
          arrowTop = tooltipRect.height;
          
          // 更新实际位置为top
          setActualPlacement('top');
          currentPlacement = 'top';
          
          // 更新CSS类
          tooltipRef.current.classList.remove('tooltip-bottom');
          tooltipRef.current.classList.add('tooltip-top');
        } else {
          top = viewportHeight - tooltipRect.height - gap;
          arrowTop = Math.min(triggerRect.top + (triggerRect.height / 2) - top - arrowSize, tooltipRect.height - arrowSize * 2);
        }
      }
      
      // 处理左右方向的切换
      if (left < 0 && currentPlacement === 'left') {
        // 如果左边放不下，切换到右边
        left = triggerRect.right + arrowSize;
        arrowLeft = -arrowSize;
        
        // 更新实际位置为right
        setActualPlacement('right');
        currentPlacement = 'right';
        
        // 更新CSS类
        tooltipRef.current.classList.remove('tooltip-left');
        tooltipRef.current.classList.add('tooltip-right');
      } else if (left + tooltipRect.width > viewportWidth && currentPlacement === 'right') {
        // 如果右边放不下，切换到左边
        left = triggerRect.left - tooltipRect.width - arrowSize;
        arrowLeft = tooltipRect.width;
        
        // 更新实际位置为left
        setActualPlacement('left');
        currentPlacement = 'left';
        
        // 更新CSS类
        tooltipRef.current.classList.remove('tooltip-right');
        tooltipRef.current.classList.add('tooltip-left');
      }
    } else {
      // 固定位置，但仍然需要确保在视口内可见
      if (currentPlacement === 'top') {
        // 如果提示框超出了顶部，增加偏移
        if (top < 0) {
          const originalTop = top;
          top = gap;
          // 调整箭头位置，使其指向触发元素
          arrowTop = arrowTop + (originalTop - top);
        }
      } else if (currentPlacement === 'bottom') {
        // 如果提示框超出了底部，减少偏移
        if (top + tooltipRect.height > viewportHeight) {
          const originalTop = top;
          top = viewportHeight - tooltipRect.height - gap;
          // 调整箭头位置，使其指向触发元素
          arrowTop = arrowTop - (originalTop - top);
        }
      } else if (currentPlacement === 'left') {
        // 如果提示框超出了左侧，增加偏移
        if (left < 0) {
          const originalLeft = left;
          left = gap;
          // 调整箭头位置，使其指向触发元素
          arrowLeft = arrowLeft + (originalLeft - left);
        }
      } else if (currentPlacement === 'right') {
        // 如果提示框超出了右侧，减少偏移
        if (left + tooltipRect.width > viewportWidth) {
          const originalLeft = left;
          left = viewportWidth - tooltipRect.width - gap;
          // 调整箭头位置，使其指向触发元素
          arrowLeft = arrowLeft - (originalLeft - left);
        }
      }
    }
    
    // 应用位置样式
    tooltipRef.current.style.position = 'fixed';
    tooltipRef.current.style.top = `${top}px`;
    tooltipRef.current.style.left = `${left}px`;
    tooltipRef.current.style.transform = 'none'; // 重置任何变换
    
    // 定位箭头
    const arrow = tooltipRef.current.querySelector('.tooltip-arrow') as HTMLElement;
    if (arrow && showArrow) {
      // 使用当前实际的位置来定位箭头
      switch (currentPlacement) {
        case 'top':
          arrow.style.bottom = `-${arrowSize}px`;
          arrow.style.left = `${arrowLeft}px`;
          arrow.style.top = 'auto';
          arrow.style.right = 'auto';
          // 设置箭头指向下方的样式
          arrow.className = 'tooltip-arrow tooltip-arrow-bottom';
          break;
        case 'bottom':
          arrow.style.top = `-${arrowSize}px`;
          arrow.style.left = `${arrowLeft}px`;
          arrow.style.bottom = 'auto';
          arrow.style.right = 'auto';
          // 设置箭头指向上方的样式
          arrow.className = 'tooltip-arrow tooltip-arrow-top';
          break;
        case 'left':
          arrow.style.right = `-${arrowSize}px`;
          arrow.style.top = `${arrowTop}px`;
          arrow.style.bottom = 'auto';
          arrow.style.left = 'auto';
          // 设置箭头指向右方的样式
          arrow.className = 'tooltip-arrow tooltip-arrow-right';
          break;
        case 'right':
          arrow.style.left = `-${arrowSize}px`;
          arrow.style.top = `${arrowTop}px`;
          arrow.style.bottom = 'auto';
          arrow.style.right = 'auto';
          // 设置箭头指向左方的样式
          arrow.className = 'tooltip-arrow tooltip-arrow-left';
          break;
      }
    }
  };
  
  // 当组件首次挂载或placement改变时，重置actualPlacement
  useEffect(() => {
    setActualPlacement(placement);
  }, [placement]);
  
  // 计算提示框位置
  useEffect(() => {
    if (!isVisible) return;
    
    // 初始化位置
    updateTooltipPosition();
    
    // 添加滚动和调整大小事件监听器
    window.addEventListener('scroll', updateTooltipPosition, true);
    window.addEventListener('resize', updateTooltipPosition);
    
    // 定期更新位置（处理内容动态变化的情况）
    const intervalId = setInterval(updateTooltipPosition, 300);
    
    // 清理函数
    return () => {
      window.removeEventListener('scroll', updateTooltipPosition, true);
      window.removeEventListener('resize', updateTooltipPosition);
      clearInterval(intervalId);
    };
  }, [isVisible, placement, maxWidth, showArrow, fixedPlacement, actualPlacement]);
  
  // 处理点击外部关闭
  useEffect(() => {
    if (trigger !== 'click' || !isVisible) return;
    
    const handleClickOutside = (event: MouseEvent) => {
      if (
        triggerRef.current && 
        !triggerRef.current.contains(event.target as Node) &&
        tooltipRef.current && 
        !tooltipRef.current.contains(event.target as Node)
      ) {
        handleVisibleChange(false);
      }
    };
    
    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, [trigger, isVisible]);
  
  // 渲染提示框内容
  const renderTooltipContent = () => {
    // 根据是否启用滚动来确定内容容器类名
    const contentClassName = scrollable ? 'tooltip-content-inner tooltip-scrollable' : 'tooltip-content-inner';
    
    if (rich) {
      return (
        <div className="tooltip-content" ref={contentRef}>
          {header && <div className="tooltip-header">{header}</div>}
          <div className={contentClassName}>{content}</div>
          {footer && <div className="tooltip-footer">{footer}</div>}
        </div>
      );
    }
    
    return (
      <div className="tooltip-content" ref={contentRef}>
        <div className={contentClassName}>{content}</div>
      </div>
    );
  };
  
  // 生成提示框类名
  const tooltipClassNames = [
    'tooltip-container',
    `tooltip-${actualPlacement}`, // 使用actualPlacement而不是placement
    `tooltip-${theme}`,
    rich ? 'tooltip-rich' : '',
    isVisible ? 'tooltip-visible' : '',
    fixedPlacement ? 'tooltip-fixed-placement' : '',
    className
  ].filter(Boolean).join(' ');
  
  // 使用Portal渲染提示框
  const tooltipPortal = isVisible && typeof document !== 'undefined'
    ? createPortal(
        <div 
          ref={tooltipRef}
          className={tooltipClassNames}
          style={{ maxWidth }}
        >
          {renderTooltipContent()}
          {showArrow && <div className="tooltip-arrow"></div>}
        </div>,
        document.body
      )
    : null;
  
  return (
    <div className="tooltip-trigger" ref={triggerRef} {...triggerEvents}>
      {children}
      {tooltipPortal}
    </div>
  );
}

export default Tooltip; 