import { Component, ErrorInfo, ReactNode } from 'react'
import ModuleErrorFallback from './ModuleErrorFallback'

/**
 * 错误边界组件
 * 
 * @description 
 * React错误边界，捕获子组件树中的JavaScript错误
 * 防止整个应用崩溃，提供友好的错误提示和恢复机制
 * 
 * @version Week 2 Day 7 - 任务17
 * 
 * @example
 * ```tsx
 * <ErrorBoundary>
 *   <YourComponent />
 * </ErrorBoundary>
 * ```
 * 
 * 注意事项：
 * - 错误边界无法捕获以下错误：
 *   1. 事件处理器中的错误（使用try-catch）
 *   2. 异步代码中的错误（使用try-catch）
 *   3. 服务端渲染的错误
 *   4. 错误边界自身的错误
 */

interface Props {
  children: ReactNode
  /** 错误回退UI（可选，默认使用ModuleErrorFallback） */
  fallback?: ReactNode
  /** 模块名称（用于错误日志） */
  moduleName?: string
}

interface State {
  hasError: boolean
  error: Error | null
  errorInfo: ErrorInfo | null
}

class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props)
    this.state = {
      hasError: false,
      error: null,
      errorInfo: null,
    }
  }

  /**
   * 当子组件抛出错误时调用
   */
  static getDerivedStateFromError(error: Error): State {
    return {
      hasError: true,
      error,
      errorInfo: null,
    }
  }

  /**
   * 错误被捕获后调用，用于记录错误日志
   */
  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    const { moduleName } = this.props
    
    // 记录错误日志（当前使用console，后续接入真实日志系统）
    console.error('🚨 ErrorBoundary caught an error:', {
      module: moduleName || 'Unknown',
      error: error.toString(),
      componentStack: errorInfo.componentStack,
      timestamp: new Date().toISOString(),
    })
    
    // 更新状态以显示错误信息
    this.setState({
      error,
      errorInfo,
    })
    
    // TODO: 接入真实日志系统
    // 例如：Sentry.captureException(error, { extra: errorInfo })
  }

  /**
   * 重置错误状态，尝试重新渲染
   */
  handleReset = () => {
    this.setState({
      hasError: false,
      error: null,
      errorInfo: null,
    })
  }

  render() {
    const { hasError, error, errorInfo } = this.state
    const { children, fallback, moduleName } = this.props

    if (hasError) {
      // 如果提供了自定义fallback，使用自定义UI
      if (fallback) {
        return fallback
      }

      // 使用默认错误提示UI
      return (
        <ModuleErrorFallback
          error={error}
          errorInfo={errorInfo}
          onReset={this.handleReset}
          moduleName={moduleName}
        />
      )
    }

    return children
  }
}

export default ErrorBoundary

/**
 * 🔧 开发说明：错误边界最佳实践
 * 
 * 1. 错误边界的放置位置：
 *    - 全局级别：App根组件
 *    - 模块级别：每个业务模块入口
 *    - 关键组件级别：复杂的第三方组件
 * 
 * 2. 错误日志：
 *    【当前阶段】console.error（开发调试）
 *    【Week 5+】接入 Sentry/LogRocket 等日志系统
 * 
 * 3. 错误恢复策略：
 *    - 提供"重试"按钮，尝试重新渲染
 *    - 提供"返回首页"按钮，避免用户卡住
 *    - 显示友好的错误提示，而非技术错误信息
 * 
 * 4. 无法捕获的错误类型：
 *    - 事件处理器：使用 try-catch
 *    - 异步代码：使用 try-catch 或 .catch()
 *    - setTimeout/setInterval：使用 try-catch 包裹回调
 * 
 * 5. 生产环境优化：
 *    - 隐藏详细错误堆栈（避免泄露代码信息）
 *    - 提供错误报告功能（用户可以反馈问题）
 *    - 记录完整错误上下文（用户操作、路由、设备信息）
 */

