/**
 * 安全的坐标映射工具类 - 渐进式增强
 * 
 * 设计原则：
 * 1. 基础功能始终可用
 * 2. 高级功能可选启用
 * 3. 错误自动回退到基础功能
 * 4. 详细的性能监控和错误日志
 */

import { 
  type CoordinateMappingConfig, 
  DEFAULT_COORDINATE_MAPPING_CONFIG,
  validateConfig
} from './CoordinateMappingConfig'

export interface DeviceInfo {
  density: number
  densityDpi: number
  hasNavigationBar: boolean
  aspectRatio: number
  realScreenSize: { width: number; height: number }
  appScreenSize: { width: number; height: number }
  navigationBarSize: { width: number; height: number }
}

export interface CoordinateMappingResult {
  x: number
  y: number
  metadata: {
    scale: number
    density: number
    actualDisplayArea: { width: number; height: number }
    offset: { x: number; y: number }
    aspectRatioDiff: number
    processingTime: number
    method: string
    errors: string[]
    warnings: string[]
  }
}

export class SafeCoordinateMapper {
  private config: CoordinateMappingConfig
  private performanceStats: {
    totalMappings: number
    successfulMappings: number
    failedMappings: number
    averageProcessingTime: number
    errorRates: { [key: string]: number }
  }

  constructor(config?: Partial<CoordinateMappingConfig>) {
    this.config = { ...DEFAULT_COORDINATE_MAPPING_CONFIG, ...config }
    this.performanceStats = {
      totalMappings: 0,
      successfulMappings: 0,
      failedMappings: 0,
      averageProcessingTime: 0,
      errorRates: {}
    }
    
    // 验证配置
    const validation = validateConfig(this.config)
    if (!validation.isValid) {
      console.error('SafeCoordinateMapper配置无效:', validation.errors)
      throw new Error('Invalid coordinate mapping configuration')
    }
    
    if (validation.warnings.length > 0) {
      console.warn('SafeCoordinateMapper配置警告:', validation.warnings)
    }
  }

  /**
   * 安全的坐标映射 - 主要入口点
   */
  mapCoordinates(
    canvasX: number,
    canvasY: number,
    canvasElement: HTMLCanvasElement,
    deviceWidth: number,
    deviceHeight: number,
    deviceInfo?: DeviceInfo
  ): CoordinateMappingResult | null {
    const startTime = performance.now()
    const errors: string[] = []
    const warnings: string[] = []
    
    try {
      this.performanceStats.totalMappings++
      
      // 🔒 阶段1：基础验证
      const basicValidation = this.validateBasicInputs(
        canvasX, canvasY, canvasElement, deviceWidth, deviceHeight
      )
      if (!basicValidation.isValid) {
        errors.push(...basicValidation.errors)
        warnings.push(...basicValidation.warnings)
        
        if (this.config.fallbackToBasicOnError) {
          return this.performBasicMapping(
            canvasX, canvasY, canvasElement, deviceWidth, deviceHeight,
            startTime, 'basic_fallback', errors, warnings
          )
        }
        return null
      }

      // 🔒 阶段2：基础坐标映射
      const basicResult = this.performBasicMapping(
        canvasX, canvasY, canvasElement, deviceWidth, deviceHeight,
        startTime, 'basic', errors, warnings
      )
      
      if (!basicResult) {
        this.performanceStats.failedMappings++
        return null
      }

      // 🔒 阶段3：渐进式增强
      const enhancedResult = this.applyEnhancements(
        basicResult, deviceInfo, deviceWidth, deviceHeight
      )
      
      // 🔒 阶段4：最终验证和统计
      const finalResult = this.validateAndFinalizeMappingResult(
        enhancedResult, deviceWidth, deviceHeight, startTime
      )
      
      this.performanceStats.successfulMappings++
      this.updatePerformanceStats(finalResult.metadata.processingTime)
      
      return finalResult
      
    } catch (error) {
      this.performanceStats.failedMappings++
      const errorMessage = `坐标映射失败: ${error instanceof Error ? error.message : 'Unknown error'}`
      console.error(errorMessage, error)
      
      if (this.config.fallbackToBasicOnError) {
        return this.performBasicMapping(
          canvasX, canvasY, canvasElement, deviceWidth, deviceHeight,
          startTime, 'error_fallback', [errorMessage], warnings
        )
      }
      
      return null
    }
  }

  /**
   * 🔒 基础输入验证
   */
  private validateBasicInputs(
    canvasX: number,
    canvasY: number,
    canvasElement: HTMLCanvasElement,
    deviceWidth: number,
    deviceHeight: number
  ): { isValid: boolean; errors: string[]; warnings: string[] } {
    const errors: string[] = []
    const warnings: string[] = []

    // 检查基础参数
    if (!canvasElement || !canvasElement.parentElement) {
      errors.push('Canvas元素或其容器不存在')
    }
    
    if (deviceWidth <= 0 || deviceHeight <= 0) {
      errors.push(`设备尺寸无效: ${deviceWidth}×${deviceHeight}`)
    }
    
    if (canvasX < 0 || canvasY < 0) {
      warnings.push('Canvas坐标为负数')
    }

    // 检查设备尺寸范围
    if (deviceWidth < this.config.minimumScreenSize.width || 
        deviceHeight < this.config.minimumScreenSize.height) {
      warnings.push('设备尺寸过小')
    }
    
    if (deviceWidth > this.config.maximumScreenSize.width || 
        deviceHeight > this.config.maximumScreenSize.height) {
      warnings.push('设备尺寸过大')
    }

    return { isValid: errors.length === 0, errors, warnings }
  }

  /**
   * 🔒 基础坐标映射 - 始终可用的核心功能
   */
  private performBasicMapping(
    canvasX: number,
    canvasY: number,
    canvasElement: HTMLCanvasElement,
    deviceWidth: number,
    deviceHeight: number,
    startTime: number,
    method: string,
    errors: string[],
    warnings: string[]
  ): CoordinateMappingResult | null {
    try {
      const container = canvasElement.parentElement!
      const containerRect = container.getBoundingClientRect()
      
      const displayWidth = containerRect.width
      const displayHeight = containerRect.height
      
      // 基础缩放计算
      const scaleX = displayWidth / deviceWidth
      const scaleY = displayHeight / deviceHeight
      const scale = Math.min(scaleX, scaleY)
      
      // 基础显示区域计算
      const actualDisplayWidth = deviceWidth * scale
      const actualDisplayHeight = deviceHeight * scale
      const offsetX = (displayWidth - actualDisplayWidth) / 2
      const offsetY = (displayHeight - actualDisplayHeight) / 2
      
      // 基础坐标转换
      const adjustedCanvasX = canvasX - offsetX
      const adjustedCanvasY = canvasY - offsetY
      
      // 检查是否在显示区域内
      if (adjustedCanvasX < 0 || adjustedCanvasX > actualDisplayWidth || 
          adjustedCanvasY < 0 || adjustedCanvasY > actualDisplayHeight) {
        return null
      }
      
      const deviceX = adjustedCanvasX / scale
      const deviceY = adjustedCanvasY / scale
      
      // 基础坐标限制
      const clampedX = Math.max(0, Math.min(deviceWidth, Math.round(deviceX)))
      const clampedY = Math.max(0, Math.min(deviceHeight, Math.round(deviceY)))
      
      const processingTime = performance.now() - startTime
      
      return {
        x: clampedX,
        y: clampedY,
        metadata: {
          scale,
          density: 1.0, // 基础密度
          actualDisplayArea: { width: actualDisplayWidth, height: actualDisplayHeight },
          offset: { x: offsetX, y: offsetY },
          aspectRatioDiff: Math.abs((deviceWidth / deviceHeight) - (displayWidth / displayHeight)),
          processingTime,
          method,
          errors: [...errors],
          warnings: [...warnings]
        }
      }
      
    } catch (error) {
      console.error('基础坐标映射失败:', error)
      return null
    }
  }

  /**
   * 🔒 渐进式增强 - 根据配置启用高级功能
   */
  private applyEnhancements(
    basicResult: CoordinateMappingResult,
    deviceInfo?: DeviceInfo,
    deviceWidth?: number,
    deviceHeight?: number
  ): CoordinateMappingResult {
    const enhanced = { ...basicResult }
    
    try {
      // 🔧 增强1：密度修正
      if (this.config.enableDensityCorrection && deviceInfo) {
        enhanced.metadata.density = deviceInfo.density
        enhanced.metadata.method += '+density'
        
        // 高密度设备的亚像素精度
        if (this.config.enableSubPixelPrecision && deviceInfo.density > 2) {
          enhanced.x = Math.round(enhanced.x * 10) / 10
          enhanced.y = Math.round(enhanced.y * 10) / 10
          enhanced.metadata.method += '+subpixel'
        }
      }
      
      // 🔧 增强2：导航栏检测
      if (this.config.enableNavigationBarDetection && deviceInfo && deviceHeight) {
        if (deviceInfo.hasNavigationBar && deviceInfo.navigationBarSize?.height > 0) {
          const navBarHeight = deviceInfo.navigationBarSize.height
          const navigationBarThreshold = deviceHeight - navBarHeight
          
          if (enhanced.y > navigationBarThreshold) {
            enhanced.y = Math.min(enhanced.y, deviceHeight + Math.min(navBarHeight, 150))
            enhanced.metadata.method += '+navbar'
          }
        }
      }
      
      // 🔧 增强3：长宽比修正
      if (this.config.enableAspectRatioCorrection && deviceInfo) {
        const aspectRatioDiff = Math.abs(deviceInfo.aspectRatio - (deviceWidth! / deviceHeight!))
        if (aspectRatioDiff > 0.1) {
          enhanced.metadata.warnings.push(`长宽比差异较大: ${aspectRatioDiff.toFixed(3)}`)
        }
      }
      
      // 🔧 增强4：设备特定优化
      if (this.config.enableDeviceSpecificOptimizations && deviceInfo && deviceWidth && deviceHeight) {
        const screenArea = deviceWidth * deviceHeight
        if (screenArea > 2073600) { // 1080p以上
          enhanced.metadata.method += '+highres'
        }
      }
      
    } catch (error) {
      enhanced.metadata.errors.push(`增强处理失败: ${error instanceof Error ? error.message : 'Unknown error'}`)
    }
    
    return enhanced
  }

  /**
   * 🔒 最终验证和结果处理
   */
  private validateAndFinalizeMappingResult(
    result: CoordinateMappingResult,
    deviceWidth: number,
    deviceHeight: number,
    startTime: number
  ): CoordinateMappingResult {
    // 最终坐标验证
    if (this.config.enableCoordinateValidation) {
      const errorX = Math.abs(result.x - Math.round(result.x))
      const errorY = Math.abs(result.y - Math.round(result.y))
      
      if (errorX > this.config.maxCoordinateError || errorY > this.config.maxCoordinateError) {
        result.metadata.warnings.push(`坐标误差过大: (${errorX.toFixed(2)}, ${errorY.toFixed(2)})`)
      }
    }
    
    // 确保坐标在边界内
    result.x = Math.max(0, Math.min(deviceWidth, result.x))
    result.y = Math.max(0, Math.min(deviceHeight, result.y))
    
    // 更新处理时间
    result.metadata.processingTime = performance.now() - startTime
    
    // 详细日志
    if (this.config.enableDetailedLogging) {
      console.log('SafeCoordinateMapper映射完成:', {
        coordinates: { x: result.x, y: result.y },
        metadata: result.metadata,
        config: this.config,
        stats: this.performanceStats
      })
    }
    
    return result
  }

  /**
   * 更新性能统计
   */
  private updatePerformanceStats(processingTime: number) {
    if (this.config.enablePerformanceMonitoring) {
      const totalTime = this.performanceStats.averageProcessingTime * (this.performanceStats.successfulMappings - 1)
      this.performanceStats.averageProcessingTime = (totalTime + processingTime) / this.performanceStats.successfulMappings
    }
  }

  /**
   * 获取性能统计报告
   */
  getPerformanceReport(): string {
    const successRate = this.performanceStats.totalMappings > 0 
      ? (this.performanceStats.successfulMappings / this.performanceStats.totalMappings * 100).toFixed(1)
      : '0'
    
    return `
SafeCoordinateMapper性能报告:
📊 总映射次数: ${this.performanceStats.totalMappings}
✅ 成功次数: ${this.performanceStats.successfulMappings}
❌ 失败次数: ${this.performanceStats.failedMappings}
📈 成功率: ${successRate}%
⏱️ 平均处理时间: ${this.performanceStats.averageProcessingTime.toFixed(2)}ms
🔧 回退模式: ${this.config.fallbackToBasicOnError ? '启用' : '禁用'}
`
  }

  /**
   * 更新配置
   */
  updateConfig(newConfig: Partial<CoordinateMappingConfig>) {
    const updatedConfig = { ...this.config, ...newConfig }
    const validation = validateConfig(updatedConfig)
    
    if (!validation.isValid) {
      console.error('配置更新失败:', validation.errors)
      return false
    }
    
    this.config = updatedConfig
    console.log('SafeCoordinateMapper配置已更新')
    return true
  }

  /**
   * 重置性能统计
   */
  resetPerformanceStats() {
    this.performanceStats = {
      totalMappings: 0,
      successfulMappings: 0,
      failedMappings: 0,
      averageProcessingTime: 0,
      errorRates: {}
    }
  }
}

export default SafeCoordinateMapper 