/**
 * 视频编辑API错误处理器
 */

import { debugLog, errorHandlingConfig } from './config';

export interface ApiError {
  code: number;
  message: string;
  details?: any;
  timestamp: string;
  endpoint?: string;
}

export interface RetryOptions {
  maxRetries?: number;
  retryDelay?: number;
  shouldRetry?: (error: ApiError) => boolean;
  onRetry?: (attempt: number, error: ApiError) => void;
}

/**
 * 创建API错误对象
 */
export function createApiError(
  code: number,
  message: string,
  details?: any,
  endpoint?: string
): ApiError {
  return {
    code,
    message,
    details,
    timestamp: new Date().toISOString(),
    endpoint
  };
}

/**
 * 判断错误是否可重试
 */
export function isRetryableError(error: ApiError): boolean {
  // 网络错误、超时、5xx服务器错误可重试
  return (
    error.code === 0 || // 网络错误
    error.code === 408 || // 请求超时
    error.code === 429 || // 请求过多
    (error.code >= 500 && error.code < 600) // 服务器错误
  );
}

/**
 * 计算重试延迟（指数退避）
 */
export function calculateRetryDelay(attempt: number, baseDelay: number = 1000): number {
  return Math.min(baseDelay * Math.pow(2, attempt - 1), 10000); // 最大10秒
}

/**
 * 带重试的API调用包装器
 */
export async function withRetry<T>(
  apiCall: () => Promise<T>,
  options: RetryOptions = {}
): Promise<T> {
  const {
    maxRetries = errorHandlingConfig.maxRetries,
    retryDelay = errorHandlingConfig.retryDelay,
    shouldRetry = isRetryableError,
    onRetry
  } = options;

  let lastError: ApiError;
  
  for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
    try {
      const result = await apiCall();
      
      // 如果之前有重试，记录成功
      if (attempt > 1) {
        debugLog(`API调用在第${attempt}次尝试后成功`);
      }
      
      return result;
    } catch (error: any) {
      // 转换为标准错误格式
      lastError = error instanceof Error 
        ? createApiError(0, error.message, error)
        : error;

      debugLog(`API调用失败 (尝试 ${attempt}/${maxRetries + 1})`, lastError);

      // 如果是最后一次尝试，或错误不可重试，直接抛出
      if (attempt > maxRetries || !shouldRetry(lastError)) {
        throw lastError;
      }

      // 计算延迟时间
      const delay = calculateRetryDelay(attempt, retryDelay);
      
      // 调用重试回调
      onRetry?.(attempt, lastError);
      
      debugLog(`${delay}ms后进行第${attempt + 1}次重试`);
      
      // 等待后重试
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  throw lastError!;
}

/**
 * API错误分类
 */
export enum ErrorCategory {
  NETWORK = 'network',
  VALIDATION = 'validation',
  AUTHENTICATION = 'authentication',
  AUTHORIZATION = 'authorization',
  NOT_FOUND = 'not_found',
  SERVER = 'server',
  UNKNOWN = 'unknown'
}

/**
 * 根据错误码分类错误
 */
export function categorizeError(error: ApiError): ErrorCategory {
  const { code } = error;
  
  if (code === 0) return ErrorCategory.NETWORK;
  if (code === 400) return ErrorCategory.VALIDATION;
  if (code === 401) return ErrorCategory.AUTHENTICATION;
  if (code === 403) return ErrorCategory.AUTHORIZATION;
  if (code === 404) return ErrorCategory.NOT_FOUND;
  if (code >= 500) return ErrorCategory.SERVER;
  
  return ErrorCategory.UNKNOWN;
}

/**
 * 获取用户友好的错误消息
 */
export function getUserFriendlyMessage(error: ApiError): string {
  const category = categorizeError(error);
  
  switch (category) {
    case ErrorCategory.NETWORK:
      return '网络连接失败，请检查网络连接后重试';
    case ErrorCategory.VALIDATION:
      return '请求参数有误，请检查输入内容';
    case ErrorCategory.AUTHENTICATION:
      return '登录已过期，请重新登录';
    case ErrorCategory.AUTHORIZATION:
      return '权限不足，无法执行此操作';
    case ErrorCategory.NOT_FOUND:
      return '请求的资源不存在';
    case ErrorCategory.SERVER:
      return '服务器暂时不可用，请稍后重试';
    default:
      return error.message || '发生未知错误';
  }
}

/**
 * 错误通知处理
 */
export function handleErrorNotification(error: ApiError): void {
  const category = categorizeError(error);
  const message = getUserFriendlyMessage(error);
  
  // 根据配置决定是否显示通知
  const { notifications } = errorHandlingConfig;
  
  let shouldNotify = false;
  
  switch (category) {
    case ErrorCategory.NETWORK:
      shouldNotify = notifications.showNetworkErrors;
      break;
    case ErrorCategory.VALIDATION:
      shouldNotify = notifications.showValidationErrors;
      break;
    case ErrorCategory.SERVER:
      shouldNotify = notifications.showServerErrors;
      break;
    default:
      shouldNotify = true;
  }
  
  if (shouldNotify) {
    // 这里可以集成实际的通知系统
    console.error('API错误通知:', message, error);
    
    // 如果有全局通知系统，在这里调用
    if (typeof window !== 'undefined' && (window as any).msg) {
      (window as any).msg.error(message);
    }
  }
}

/**
 * 错误恢复策略
 */
export interface RecoveryStrategy {
  name: string;
  canRecover: (error: ApiError) => boolean;
  recover: (error: ApiError) => Promise<any>;
}

/**
 * Mock API回退策略
 */
export const mockFallbackStrategy: RecoveryStrategy = {
  name: 'mock-fallback',
  canRecover: (error: ApiError) => {
    return errorHandlingConfig.fallbackToMock && 
           (error.code === 404 || error.code >= 500);
  },
  recover: async (error: ApiError) => {
    debugLog('API失败，回退到Mock模式', error);
    // 这里可以动态切换到Mock API
    return null;
  }
};

/**
 * 缓存回退策略
 */
export const cacheStrategy: RecoveryStrategy = {
  name: 'cache-fallback',
  canRecover: (error: ApiError) => {
    return error.code === 0 || error.code >= 500;
  },
  recover: async (error: ApiError) => {
    debugLog('尝试从缓存恢复数据', error);
    // 这里可以从本地缓存获取数据
    return null;
  }
};

/**
 * 默认恢复策略列表
 */
export const defaultRecoveryStrategies: RecoveryStrategy[] = [
  cacheStrategy,
  mockFallbackStrategy
];

/**
 * 尝试错误恢复
 */
export async function attemptRecovery(
  error: ApiError,
  strategies: RecoveryStrategy[] = defaultRecoveryStrategies
): Promise<any> {
  for (const strategy of strategies) {
    if (strategy.canRecover(error)) {
      try {
        debugLog(`尝试恢复策略: ${strategy.name}`);
        const result = await strategy.recover(error);
        if (result !== null) {
          debugLog(`恢复策略 ${strategy.name} 成功`);
          return result;
        }
      } catch (recoveryError) {
        debugLog(`恢复策略 ${strategy.name} 失败`, recoveryError);
      }
    }
  }
  
  debugLog('所有恢复策略都失败了');
  return null;
}

/**
 * 完整的错误处理流程
 */
export async function handleApiError(error: any, endpoint?: string): Promise<any> {
  // 标准化错误格式
  const apiError: ApiError = error instanceof Error
    ? createApiError(0, error.message, error, endpoint)
    : { ...error, endpoint };

  // 记录错误
  debugLog('API错误', apiError);

  // 显示通知
  handleErrorNotification(apiError);

  // 尝试恢复
  const recoveryResult = await attemptRecovery(apiError);
  if (recoveryResult !== null) {
    return recoveryResult;
  }

  // 抛出错误
  throw apiError;
}
