/**
 * 现代化通知组件
 * 提供优雅的通知提示功能
 */

import React, { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import {
  CheckCircleIcon,
  ExclamationTriangleIcon,
  XCircleIcon,
  InformationCircleIcon,
  XMarkIcon,
} from '@heroicons/react/24/outline';
import { cn } from '../../utils/cn';

export type ToastType = 'success' | 'error' | 'warning' | 'info';

export interface ToastProps {
  id: string;
  type: ToastType;
  title: string;
  message?: string;
  duration?: number;
  onClose: (id: string) => void;
  action?: {
    label: string;
    onClick: () => void;
  };
}

const toastIcons = {
  success: CheckCircleIcon,
  error: XCircleIcon,
  warning: ExclamationTriangleIcon,
  info: InformationCircleIcon,
};

const toastStyles = {
  success: 'bg-green-50 border-green-200 text-green-800',
  error: 'bg-red-50 border-red-200 text-red-800',
  warning: 'bg-yellow-50 border-yellow-200 text-yellow-800',
  info: 'bg-blue-50 border-blue-200 text-blue-800',
};

const iconStyles = {
  success: 'text-green-600',
  error: 'text-red-600',
  warning: 'text-yellow-600',
  info: 'text-blue-600',
};

export const Toast: React.FC<ToastProps> = ({
  id,
  type,
  title,
  message,
  duration = 5000,
  onClose,
  action,
}) => {
  const [isVisible, setIsVisible] = useState(false);
  const [isLeaving, setIsLeaving] = useState(false);

  const Icon = toastIcons[type];

  useEffect(() => {
    // 入场动画
    setTimeout(() => setIsVisible(true), 10);

    // 自动关闭
    if (duration > 0) {
      const timer = setTimeout(() => {
        handleClose();
      }, duration);

      return () => clearTimeout(timer);
    }
  }, [duration]);

  const handleClose = () => {
    setIsLeaving(true);
    setTimeout(() => {
      onClose(id);
    }, 300);
  };

  return (
    <div
      className={cn(
        'flex items-start p-4 rounded-lg border shadow-lg transition-all duration-300 ease-out transform',
        toastStyles[type],
        isVisible && !isLeaving ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0',
        'max-w-sm w-full'
      )}
    >
      <div className="flex-shrink-0">
        <Icon className={cn('w-5 h-5', iconStyles[type])} />
      </div>
      
      <div className="ml-3 flex-1">
        <div className="font-medium">{title}</div>
        {message && (
          <div className="mt-1 text-sm opacity-90">{message}</div>
        )}
        
        {action && (
          <div className="mt-2">
            <button
              onClick={action.onClick}
              className="text-sm font-medium underline hover:no-underline"
            >
              {action.label}
            </button>
          </div>
        )}
      </div>
      
      <div className="ml-4 flex-shrink-0">
        <button
          onClick={handleClose}
          className="inline-flex text-gray-400 hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 rounded"
        >
          <XMarkIcon className="w-4 h-4" />
        </button>
      </div>
    </div>
  );
};

// Toast 容器
export interface ToastContainerProps {
  toasts: ToastProps[];
  position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';
}

const positionStyles = {
  'top-right': 'top-4 right-4',
  'top-left': 'top-4 left-4',
  'bottom-right': 'bottom-4 right-4',
  'bottom-left': 'bottom-4 left-4',
  'top-center': 'top-4 left-1/2 transform -translate-x-1/2',
  'bottom-center': 'bottom-4 left-1/2 transform -translate-x-1/2',
};

export const ToastContainer: React.FC<ToastContainerProps> = ({
  toasts,
  position = 'top-right',
}) => {
  if (toasts.length === 0) return null;

  const containerContent = (
    <div
      className={cn(
        'fixed z-50 flex flex-col space-y-2',
        positionStyles[position]
      )}
    >
      {toasts.map((toast) => (
        <Toast key={toast.id} {...toast} />
      ))}
    </div>
  );

  return createPortal(containerContent, document.body);
};

// Toast Hook
export interface ToastOptions {
  type?: ToastType;
  duration?: number;
  action?: {
    label: string;
    onClick: () => void;
  };
}

class ToastManager {
  private toasts: ToastProps[] = [];
  private listeners: Array<(toasts: ToastProps[]) => void> = [];

  subscribe(listener: (toasts: ToastProps[]) => void) {
    this.listeners.push(listener);
    return () => {
      this.listeners = this.listeners.filter(l => l !== listener);
    };
  }

  private notify() {
    this.listeners.forEach(listener => listener([...this.toasts]));
  }

  show(title: string, message?: string, options: ToastOptions = {}) {
    const id = Math.random().toString(36).substr(2, 9);
    const toast: ToastProps = {
      id,
      type: options.type || 'info',
      title,
      message,
      duration: options.duration,
      action: options.action,
      onClose: this.dismiss.bind(this),
    };

    this.toasts.push(toast);
    this.notify();
    return id;
  }

  success(title: string, message?: string, options?: Omit<ToastOptions, 'type'>) {
    return this.show(title, message, { ...options, type: 'success' });
  }

  error(title: string, message?: string, options?: Omit<ToastOptions, 'type'>) {
    return this.show(title, message, { ...options, type: 'error' });
  }

  warning(title: string, message?: string, options?: Omit<ToastOptions, 'type'>) {
    return this.show(title, message, { ...options, type: 'warning' });
  }

  info(title: string, message?: string, options?: Omit<ToastOptions, 'type'>) {
    return this.show(title, message, { ...options, type: 'info' });
  }

  dismiss(id: string) {
    this.toasts = this.toasts.filter(toast => toast.id !== id);
    this.notify();
  }

  clear() {
    this.toasts = [];
    this.notify();
  }
}

export const toast = new ToastManager();

// React Hook
export const useToast = () => {
  const [toasts, setToasts] = useState<ToastProps[]>([]);

  useEffect(() => {
    return toast.subscribe(setToasts);
  }, []);

  return {
    toasts,
    toast: {
      show: toast.show.bind(toast),
      success: toast.success.bind(toast),
      error: toast.error.bind(toast),
      warning: toast.warning.bind(toast),
      info: toast.info.bind(toast),
      dismiss: toast.dismiss.bind(toast),
      clear: toast.clear.bind(toast),
    },
  };
};
