/**
 * 轻量级顶部通知组件
 * 
 * 在页面顶部显示简单的提示信息，带有图标，自动换行，有最大宽度和高度限制
 * 支持自动关闭、点击关闭
 * 能根据文字长度自动调整宽度，超出最大宽度则自动换行
 */

import { useState, useEffect, useCallback } from 'react';
import { createPortal } from 'react-dom';
import toastStyles from '~/styles/components/toast.css?url';

// 通知类型
export type ToastType = 'success' | 'error' | 'warning' | 'info';

// 组件属性
interface ToastProps {
  // 是否显示通知
  isOpen: boolean;
  // 关闭通知的回调
  onClose: () => void;
  // 通知内容
  message: string;
  // 通知类型
  type?: ToastType;
  // 是否自动关闭
  autoClose?: boolean;
  // 自动关闭的延迟时间（毫秒）
  autoCloseDelay?: number;
  // 自定义图标
  customIcon?: React.ReactNode;
  // 自定义CSS类名
  className?: string;
}

// 默认自动关闭延迟
const DEFAULT_AUTO_CLOSE_DELAY = 3000;

// 导出样式
export function links() {
  return [{ rel: 'stylesheet', href: toastStyles }];
}

export function Toast({
  isOpen,
  onClose,
  message,
  type = 'info',
  autoClose = true,
  autoCloseDelay = DEFAULT_AUTO_CLOSE_DELAY,
  customIcon,
  className = ''
}: ToastProps) {
  const [isClosing, setIsClosing] = useState(false);
  const [portalElement, setPortalElement] = useState<HTMLElement | null>(null);
  const [messageLines, setMessageLines] = useState<number>(1);
  const [isHovered, setIsHovered] = useState(false);

  // 在客户端渲染时获取 portal 容器
  useEffect(() => {
    if (typeof document !== 'undefined') {
      let element = document.getElementById('toast-portal');
      if (!element) {
        element = document.createElement('div');
        element.id = 'toast-portal';
        element.className = 'toast-container';
        document.body.appendChild(element);
      }
      setPortalElement(element);
    }
  }, []);

  // 计算消息行数（用于可能的额外样式调整）
  useEffect(() => {
    if (message) {
      // 更好地估算中文文本行数：假设每行平均25个中文字符(或50个英文字符)
      const estimatedChars = message.split('').reduce((count, char) => {
        // 判断是否为中文字符(粗略判断)
        const isChinese = /[\u4e00-\u9fa5]/.test(char);
        return count + (isChinese ? 2 : 1); // 中文字符算2个宽度单位
      }, 0);
      
      const estimatedLines = Math.ceil(estimatedChars / 50);
      setMessageLines(Math.max(1, Math.min(estimatedLines, 10))); // 最小1行，最大10行
    }
  }, [message]);

  // 处理关闭动画
  const handleClose = useCallback(() => {
    setIsClosing(true);
    setTimeout(() => {
      setIsClosing(false);
      onClose();
    }, 300); // 动画持续时间
  }, [onClose]);

  // 自动关闭
  useEffect(() => {
    if (isOpen && autoClose && !isHovered) {
      // const messageLength = message.length;
      // const baseDelay = autoCloseDelay || DEFAULT_AUTO_CLOSE_DELAY;
      
      // // 按照文本长度比例延长显示时间
      // const adjustedDelay = Math.min(
      //   baseDelay + (messageLength > 20 ? messageLength * 30 : 0), 
      //   15000 // 最长不超过15秒
      // );
      // 不再根据消息长度调整显示时间，使用固定的延迟时间
      const delay = autoCloseDelay || DEFAULT_AUTO_CLOSE_DELAY;
      
      const timer = setTimeout(() => {
        handleClose();
      // }, adjustedDelay);
      }, delay);
      
      return () => clearTimeout(timer);
    }
  // }, [isOpen, autoClose, autoCloseDelay, handleClose, message, isHovered]);
  }, [isOpen, autoClose, autoCloseDelay, handleClose, isHovered]);

  // 鼠标悬停处理
  const handleMouseEnter = () => {
    setIsHovered(true);
  };

  const handleMouseLeave = () => {
    setIsHovered(false);
  };

  // 渲染图标
  const renderIcon = () => {
    if (customIcon) {
      return customIcon;
    }

    switch (type) {
      case 'success':
        return <i className="ri-check-line toast-icon success"></i>;
      case 'error':
        return <i className="ri-close-circle-line toast-icon error"></i>;
      case 'warning':
        return <i className="ri-alert-line toast-icon warning"></i>;
      case 'info':
      default:
        return <i className="ri-information-line toast-icon info"></i>;
    }
  };

  // 键盘事件处理
  const handleKeyDown = useCallback((e: React.KeyboardEvent) => {
    if (e.key === 'Escape') {
      handleClose();
    }
  }, [handleClose]);

  // 处理长文本
  const formatMessage = (text: string) => {
    // 清理文本中的多余空白，但保留换行符
    const cleanedText = text.replace(/[ \t]+/g, ' ');

    // 处理中文文本最后两个字符换行问题
    const fixChineseWrapping = (content: string) => {
      // 如果内容长度小于3，或已有换行符，直接返回
      if (content.length < 3 || content.includes('\n')) {
        return content;
      }
      
      // 检测是否是中文文本
      const isChinese = /[\u4e00-\u9fa5]/.test(content);
      if (!isChinese) {
        return content;
      }
      
      // 在中文文本中，添加零宽空格避免最后两个字符换行
      // 在文本末尾前两个字符之间添加零宽不换行空格，防止它们被分开
      return content.slice(0, -2) + '\u2060' + content.slice(-2);
    };
    
    // 如果文本包含换行符，按换行符分割
    if (cleanedText.includes('\n')) {
      return cleanedText.split('\n').map((line, index) => (
        <div key={index} className="toast-message-line">
          {fixChineseWrapping(line)}
        </div>
      ));
    }
    
    // 如果没有换行符，直接返回整个文本，应用修复
    return fixChineseWrapping(cleanedText);
  };

  // 如果通知未打开，不渲染
  if (!isOpen || !portalElement) {
    return null;
  }

  // 使用 Portal 渲染通知
  return createPortal(
    <div 
      className={`toast toast-${type} ${isClosing ? 'closing' : ''} ${className} ${messageLines > 1 ? 'toast-multiline' : ''}`}
      role="status"
      aria-live="polite"
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
    >
      <div className="toast-content">
        <div className="toast-icon-wrapper">
          {renderIcon()}
        </div>
        <div className="toast-message">
          {formatMessage(message)}
        </div>
      </div>
      <button 
        className="toast-close" 
        onClick={handleClose}
        aria-label="关闭"
        onKeyDown={handleKeyDown}
      >
        <i className="ri-close-line"></i>
      </button>
    </div>,
    portalElement
  );
}

// 创建全局通知服务
type ShowToastOptions = Omit<ToastProps, 'isOpen' | 'onClose'>;

class ToastService {
  private static instance: ToastService;
  private showToast: ((options: ShowToastOptions) => void) | null = null;

  private constructor() {}

  static getInstance(): ToastService {
    if (!ToastService.instance) {
      ToastService.instance = new ToastService();
    }
    return ToastService.instance;
  }

  registerShowToast(showFn: (options: ShowToastOptions) => void): void {
    this.showToast = showFn;
  }

  success(message: string, options?: Partial<ShowToastOptions>): void {
    this.show({ ...options, message, type: 'success' });
  }

  error(message: string, options?: Partial<ShowToastOptions>): void {
    this.show({ ...options, message, type: 'error' });
  }

  warning(message: string, options?: Partial<ShowToastOptions>): void {
    this.show({ ...options, message, type: 'warning' });
  }

  info(message: string, options?: Partial<ShowToastOptions>): void {
    this.show({ ...options, message, type: 'info' });
  }

  show(options: ShowToastOptions): void {
    if (this.showToast) {
      this.showToast(options);
    } else {
      console.error('ToastService: showToast is not registered');
    }
  }
}

export const toastService = ToastService.getInstance();

/**
 * 全局通知容器
 * 用于在应用根组件中挂载通知服务
 */
export function ToastProvider({ children }: { children: React.ReactNode }) {
  const [toastQueue, setToastQueue] = useState<(ShowToastOptions & { id: string })[]>([]);
  const maxToasts = 5; // 增加最大显示的通知数量

  useEffect(() => {
    toastService.registerShowToast((options) => {
      const id = Math.random().toString(36).substring(2, 9);
      
      setToastQueue(prev => {
        // 如果已经有太多通知，移除最早的
        if (prev.length >= maxToasts) {
          return [...prev.slice(1), { ...options, id }];
        }
        return [...prev, { ...options, id }];
      });
    });
  }, []);

  const handleCloseToast = (id: string) => {
    setToastQueue(prev => prev.filter(toast => toast.id !== id));
  };

  return (
    <>
      {children}
      {toastQueue.map((toast) => (
        <Toast
          key={toast.id}
          isOpen={true}
          onClose={() => handleCloseToast(toast.id)}
          message={toast.message}
          type={toast.type}
          autoClose={toast.autoClose !== undefined ? toast.autoClose : true}
          autoCloseDelay={toast.autoCloseDelay}
          customIcon={toast.customIcon}
          className={toast.className}
        />
      ))}
    </>
  );
} 