/**
 * 统一交易所适配器错误处理工具
 */

export interface AdapterError {
  code: string
  message: string
  exchange: string
  originalError?: any
  retryable: boolean
  severity: 'low' | 'medium' | 'high' | 'critical'
}

export class AdapterErrorHandler {
  /**
   * 标准化错误处理
   */
  static handleError(exchange: string, error: any, method: string): AdapterError {
    const originalMessage = this.extractErrorMessage(error)
    const code = this.extractErrorCode(error, exchange)

    // 根据错误码判断是否可重试和严重程度
    const { retryable, severity } = this.analyzeError(code, exchange)

    const adapterError: AdapterError = {
      code,
      message: `[${exchange}:${method}] ${originalMessage}`,
      exchange,
      originalError: error,
      retryable,
      severity,
    }

    // 记录日志
    this.logError(adapterError, method)

    return adapterError
  }

  /**
   * 提取错误信息
   */
  private static extractErrorMessage(error: any): string {
    if (typeof error === 'string') return error
    if (error?.message) return error.message
    if (error?.msg) return error.msg
    if (error?.reason) return error.reason
    return '未知错误'
  }

  /**
   * 提取错误代码
   */
  private static extractErrorCode(error: any, exchange: string): string {
    // Binance 风格错误码
    if (error?.code) return String(error.code)

    // HTTP 状态码
    if (error?.status) return `HTTP_${error.status}`
    if (error?.response?.status) return `HTTP_${error.response.status}`

    // Pacifica 特殊情况
    if (exchange === 'pacifica' && error?.message?.includes('403')) return 'HTTP_403'

    // Aster 特殊情况
    if (exchange === 'aster' && error?.message?.includes('-2019')) return 'INSUFFICIENT_MARGIN'

    return 'UNKNOWN_ERROR'
  }

  /**
   * 分析错误属性
   */
  private static analyzeError(
    code: string,
    exchange: string,
  ): { retryable: boolean; severity: 'low' | 'medium' | 'high' | 'critical' } {
    // 通用 HTTP 错误
    if (code.startsWith('HTTP_')) {
      const statusCode = parseInt(code.replace('HTTP_', ''))
      if (statusCode >= 500) return { retryable: true, severity: 'high' }
      if (statusCode === 429) return { retryable: true, severity: 'medium' }
      if (statusCode === 403) return { retryable: false, severity: 'medium' }
      if (statusCode === 401) return { retryable: false, severity: 'high' }
      return { retryable: false, severity: 'medium' }
    }

    // 交易所特定错误
    if (exchange === 'binance') {
      return this.analyzeBinanceError(code)
    } else if (exchange === 'aster') {
      return this.analyzeAsterError(code)
    } else if (exchange === 'pacifica') {
      return this.analyzePacificaError(code)
    }

    return { retryable: false, severity: 'medium' }
  }

  /**
   * 分析币安错误
   */
  private static analyzeBinanceError(code: string): {
    retryable: boolean
    severity: 'low' | 'medium' | 'high' | 'critical'
  } {
    const retryableCodes = ['-1001', '-1021', '-2013', '-2015'] // 网络、时间同步等
    const criticalCodes = ['-1022', '-2010', '-4028'] // API密钥、余额不足等
    const marginCodes = ['-2019', '-4061'] // 保证金相关

    if (retryableCodes.includes(code)) return { retryable: true, severity: 'medium' }
    if (criticalCodes.includes(code)) return { retryable: false, severity: 'critical' }
    if (marginCodes.includes(code)) return { retryable: false, severity: 'high' }

    return { retryable: false, severity: 'medium' }
  }

  /**
   * 分析Aster错误
   */
  private static analyzeAsterError(code: string): {
    retryable: boolean
    severity: 'low' | 'medium' | 'high' | 'critical'
  } {
    if (code === 'INSUFFICIENT_MARGIN') return { retryable: false, severity: 'high' }
    if (code === 'missing_user_signer_privateKey') return { retryable: false, severity: 'critical' }
    if (code === 'listenKeyExpired') return { retryable: true, severity: 'medium' }

    return { retryable: false, severity: 'medium' }
  }

  /**
   * 分析Pacifica错误
   */
  private static analyzePacificaError(code: string): {
    retryable: boolean
    severity: 'low' | 'medium' | 'high' | 'critical'
  } {
    if (code === 'HTTP_403') return { retryable: false, severity: 'medium' } // CDN/白名单
    if (code === 'orderbook_not_found') return { retryable: true, severity: 'medium' }

    return { retryable: false, severity: 'medium' }
  }

  /**
   * 记录错误日志
   */
  private static logError(error: AdapterError, method: string) {
    const level =
      error.severity === 'critical'
        ? 'error'
        : error.severity === 'high'
        ? 'error'
        : error.severity === 'medium'
        ? 'warn'
        : 'info'

    const logMessage = `${error.message} [代码: ${error.code}, 可重试: ${error.retryable}]`

    // 这里可以集成实际的日志系统
    if (level === 'error') {
      console.error(`❌ ${logMessage}`)
    } else if (level === 'warn') {
      console.warn(`⚠️ ${logMessage}`)
    } else {
      console.info(`ℹ️ ${logMessage}`)
    }
  }

  /**
   * 检查是否应该重试
   */
  static shouldRetry(error: AdapterError, attemptCount: number, maxAttempts = 3): boolean {
    return error.retryable && attemptCount < maxAttempts
  }

  /**
   * 计算重试延迟（指数退避）
   */
  static getRetryDelay(attemptCount: number, baseDelayMs = 1000, maxDelayMs = 10000): number {
    const delay = Math.min(baseDelayMs * Math.pow(2, attemptCount - 1), maxDelayMs)
    // 添加随机抖动避免雷群效应
    return delay + Math.random() * 1000
  }
}

/**
 * 装饰器：为适配器方法添加错误处理和重试逻辑
 */
export function withErrorHandling(exchange: string, maxRetries = 2) {
  return function (target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const method = descriptor.value

    descriptor.value = async function (...args: any[]) {
      let lastError: AdapterError | null = null

      for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
        try {
          return await method.apply(this, args)
        } catch (error) {
          const adapterError = AdapterErrorHandler.handleError(exchange, error, propertyName)
          lastError = adapterError

          if (!AdapterErrorHandler.shouldRetry(adapterError, attempt, maxRetries + 1)) {
            throw adapterError
          }

          const delay = AdapterErrorHandler.getRetryDelay(attempt)
          console.info(`🔄 [${exchange}:${propertyName}] 重试第 ${attempt} 次，${delay}ms 后重试`)
          await new Promise(resolve => setTimeout(resolve, delay))
        }
      }

      throw lastError
    }
  }
}
