/**
 * 统一错误处理中间件
 * 处理应用程序中的所有错误，提供统一的错误响应格式
 */

const { logger } = require('../utils/logger');

/**
 * 自定义错误类
 */
class AppError extends Error {
  constructor(message, statusCode, errorCode = null) {
    super(message);
    this.statusCode = statusCode;
    this.errorCode = errorCode;
    this.isOperational = true;

    Error.captureStackTrace(this, this.constructor);
  }
}

/**
 * 异步错误捕获包装器
 * @param {Function} fn - 异步函数
 * @returns {Function} 包装后的函数
 */
const catchAsync = (fn) => {
  return (req, res, next) => {
    fn(req, res, next).catch(next);
  };
};

/**
 * 处理数据库错误
 * @param {Error} err - 数据库错误
 * @returns {AppError} 应用错误
 */
const handleDatabaseError = (err) => {
  if (err.code === 'ER_DUP_ENTRY') {
    return new AppError('数据已存在，请检查输入信息', 400, 'DUPLICATE_ENTRY');
  }
  
  if (err.code === 'ER_NO_REFERENCED_ROW_2') {
    return new AppError('关联数据不存在', 400, 'FOREIGN_KEY_CONSTRAINT');
  }
  
  if (err.code === 'ER_ROW_IS_REFERENCED_2') {
    return new AppError('数据正在被使用，无法删除', 400, 'REFERENCED_DATA');
  }
  
  if (err.code === 'ER_DATA_TOO_LONG') {
    return new AppError('输入数据过长', 400, 'DATA_TOO_LONG');
  }
  
  if (err.code === 'ER_BAD_NULL_ERROR') {
    return new AppError('必填字段不能为空', 400, 'REQUIRED_FIELD_MISSING');
  }
  
  return new AppError('数据库操作失败', 500, 'DATABASE_ERROR');
};

/**
 * 处理JWT错误
 * @param {Error} err - JWT错误
 * @returns {AppError} 应用错误
 */
const handleJWTError = (err) => {
  if (err.name === 'JsonWebTokenError') {
    return new AppError('无效的访问令牌', 401, 'INVALID_TOKEN');
  }
  
  if (err.name === 'TokenExpiredError') {
    return new AppError('访问令牌已过期', 401, 'TOKEN_EXPIRED');
  }
  
  return new AppError('令牌验证失败', 401, 'TOKEN_VERIFICATION_FAILED');
};

/**
 * 处理验证错误
 * @param {Error} err - 验证错误
 * @returns {AppError} 应用错误
 */
const handleValidationError = (err) => {
  if (err.name === 'ValidationError') {
    const errors = Object.values(err.errors).map(e => e.message);
    return new AppError(`数据验证失败: ${errors.join(', ')}`, 400, 'VALIDATION_ERROR');
  }
  
  return new AppError('数据格式错误', 400, 'INVALID_DATA_FORMAT');
};

/**
 * 处理文件上传错误
 * @param {Error} err - 文件上传错误
 * @returns {AppError} 应用错误
 */
const handleFileUploadError = (err) => {
  if (err.code === 'LIMIT_FILE_SIZE') {
    return new AppError('文件大小超出限制', 400, 'FILE_TOO_LARGE');
  }
  
  if (err.code === 'LIMIT_FILE_COUNT') {
    return new AppError('文件数量超出限制', 400, 'TOO_MANY_FILES');
  }
  
  if (err.code === 'LIMIT_UNEXPECTED_FILE') {
    return new AppError('不支持的文件类型', 400, 'UNSUPPORTED_FILE_TYPE');
  }
  
  return new AppError('文件上传失败', 400, 'FILE_UPLOAD_ERROR');
};

/**
 * 发送错误响应
 * @param {Error} err - 错误对象
 * @param {Object} req - 请求对象
 * @param {Object} res - 响应对象
 */
const sendErrorResponse = (err, req, res) => {
  const { statusCode, message, errorCode } = err;
  
  // 构建错误响应
  const errorResponse = {
    success: false,
    message: message || '服务器内部错误',
    error_code: errorCode || 'INTERNAL_ERROR',
    timestamp: new Date().toISOString(),
    path: req.originalUrl,
    method: req.method
  };
  
  // 开发环境下包含错误堆栈
  if (process.env.NODE_ENV === 'development') {
    errorResponse.stack = err.stack;
    errorResponse.details = err;
  }
  
  // 记录错误日志
  logger.error('API Error:', {
    message: err.message,
    statusCode,
    errorCode,
    path: req.originalUrl,
    method: req.method,
    userAgent: req.get('User-Agent'),
    ip: req.ip,
    userId: req.user?.id,
    stack: err.stack
  });
  
  res.status(statusCode).json(errorResponse);
};

/**
 * 全局错误处理中间件
 * @param {Error} err - 错误对象
 * @param {Object} req - 请求对象
 * @param {Object} res - 响应对象
 * @param {Function} next - 下一个中间件
 */
const globalErrorHandler = (err, req, res, next) => {
  // 设置默认错误状态码
  err.statusCode = err.statusCode || 500;
  
  let error = { ...err };
  error.message = err.message;
  
  // 处理不同类型的错误
  if (err.code && err.code.startsWith('ER_')) {
    error = handleDatabaseError(err);
  } else if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
    error = handleJWTError(err);
  } else if (err.name === 'ValidationError') {
    error = handleValidationError(err);
  } else if (err.code && err.code.startsWith('LIMIT_')) {
    error = handleFileUploadError(err);
  } else if (err.name === 'CastError') {
    error = new AppError('无效的数据格式', 400, 'INVALID_DATA_FORMAT');
  } else if (err.code === 'ENOENT') {
    error = new AppError('文件不存在', 404, 'FILE_NOT_FOUND');
  } else if (err.code === 'EACCES') {
    error = new AppError('文件访问权限不足', 403, 'FILE_ACCESS_DENIED');
  }
  
  // 如果不是操作性错误，设置为服务器错误
  if (!error.isOperational) {
    error.statusCode = 500;
    error.message = '服务器内部错误';
    error.errorCode = 'INTERNAL_ERROR';
  }
  
  sendErrorResponse(error, req, res);
};

/**
 * 处理未找到的路由
 * @param {Object} req - 请求对象
 * @param {Object} res - 响应对象
 * @param {Function} next - 下一个中间件
 */
const notFoundHandler = (req, res, next) => {
  const err = new AppError(`路由 ${req.originalUrl} 不存在`, 404, 'ROUTE_NOT_FOUND');
  next(err);
};

/**
 * 处理未捕获的Promise拒绝
 */
process.on('unhandledRejection', (reason, promise) => {
  logger.error('Unhandled Rejection at:', promise, 'reason:', reason);
  // 优雅关闭服务器
  process.exit(1);
});

/**
 * 处理未捕获的异常
 */
process.on('uncaughtException', (err) => {
  logger.error('Uncaught Exception:', err);
  // 优雅关闭服务器
  process.exit(1);
});

/**
 * 常用错误类型
 */
const ErrorTypes = {
  // 认证相关
  UNAUTHORIZED: (message = '未授权访问') => new AppError(message, 401, 'UNAUTHORIZED'),
  FORBIDDEN: (message = '权限不足') => new AppError(message, 403, 'FORBIDDEN'),
  TOKEN_EXPIRED: (message = '访问令牌已过期') => new AppError(message, 401, 'TOKEN_EXPIRED'),
  
  // 数据相关
  NOT_FOUND: (message = '资源不存在') => new AppError(message, 404, 'NOT_FOUND'),
  DUPLICATE_ENTRY: (message = '数据已存在') => new AppError(message, 400, 'DUPLICATE_ENTRY'),
  VALIDATION_ERROR: (message = '数据验证失败') => new AppError(message, 400, 'VALIDATION_ERROR'),
  
  // 业务相关
  BUSINESS_ERROR: (message = '业务处理失败') => new AppError(message, 400, 'BUSINESS_ERROR'),
  INSUFFICIENT_BALANCE: (message = '余额不足') => new AppError(message, 400, 'INSUFFICIENT_BALANCE'),
  OPERATION_NOT_ALLOWED: (message = '操作不被允许') => new AppError(message, 400, 'OPERATION_NOT_ALLOWED'),
  
  // 系统相关
  INTERNAL_ERROR: (message = '服务器内部错误') => new AppError(message, 500, 'INTERNAL_ERROR'),
  SERVICE_UNAVAILABLE: (message = '服务暂不可用') => new AppError(message, 503, 'SERVICE_UNAVAILABLE'),
  RATE_LIMIT_EXCEEDED: (message = '请求频率超出限制') => new AppError(message, 429, 'RATE_LIMIT_EXCEEDED'),
  
  // 文件相关
  FILE_TOO_LARGE: (message = '文件大小超出限制') => new AppError(message, 400, 'FILE_TOO_LARGE'),
  UNSUPPORTED_FILE_TYPE: (message = '不支持的文件类型') => new AppError(message, 400, 'UNSUPPORTED_FILE_TYPE'),
  FILE_UPLOAD_ERROR: (message = '文件上传失败') => new AppError(message, 400, 'FILE_UPLOAD_ERROR')
};

module.exports = {
  AppError,
  catchAsync,
  globalErrorHandler,
  notFoundHandler,
  ErrorTypes
};