/**
 * 文件上传中间件
 * 支持图片上传、文件类型验证、大小限制等功能
 */

const multer = require('multer');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const sharp = require('sharp');
const { AppError, ErrorTypes } = require('./errorHandler');
const { logSystemEvent, logError } = require('../utils/logger');

// 确保上传目录存在
const uploadDir = path.join(__dirname, '../../uploads');
const avatarDir = path.join(uploadDir, 'avatars');
const animalDir = path.join(uploadDir, 'animals');
const travelDir = path.join(uploadDir, 'travels');
const documentDir = path.join(uploadDir, 'documents');

[uploadDir, avatarDir, animalDir, travelDir, documentDir].forEach(dir => {
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
});

/**
 * 生成唯一文件名
 * @param {string} originalName - 原始文件名
 * @returns {string} 唯一文件名
 */
const generateUniqueFileName = (originalName) => {
  const timestamp = Date.now();
  const randomString = crypto.randomBytes(8).toString('hex');
  const ext = path.extname(originalName).toLowerCase();
  return `${timestamp}_${randomString}${ext}`;
};

/**
 * 获取文件存储目录
 * @param {string} type - 文件类型
 * @returns {string} 存储目录路径
 */
const getStorageDir = (type) => {
  switch (type) {
    case 'avatar':
      return avatarDir;
    case 'animal':
      return animalDir;
    case 'travel':
      return travelDir;
    case 'document':
      return documentDir;
    default:
      return uploadDir;
  }
};

/**
 * 文件过滤器
 * @param {string} type - 文件类型
 * @returns {Function} 过滤器函数
 */
const createFileFilter = (type) => {
  return (req, file, cb) => {
    try {
      let allowedTypes = [];
      let allowedMimes = [];
      
      switch (type) {
        case 'image':
          allowedTypes = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
          allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
          break;
        case 'document':
          allowedTypes = ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.txt'];
          allowedMimes = [
            'application/pdf',
            'application/msword',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'application/vnd.ms-excel',
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'text/plain'
          ];
          break;
        case 'avatar':
          allowedTypes = ['.jpg', '.jpeg', '.png'];
          allowedMimes = ['image/jpeg', 'image/png'];
          break;
        default:
          allowedTypes = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.pdf', '.doc', '.docx'];
          allowedMimes = [
            'image/jpeg', 'image/png', 'image/gif', 'image/webp',
            'application/pdf', 'application/msword',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
          ];
      }
      
      const fileExt = path.extname(file.originalname).toLowerCase();
      
      if (allowedTypes.includes(fileExt) && allowedMimes.includes(file.mimetype)) {
        cb(null, true);
      } else {
        cb(new AppError(`不支持的文件类型。允许的类型: ${allowedTypes.join(', ')}`, 400, 'UNSUPPORTED_FILE_TYPE'));
      }
    } catch (error) {
      cb(error);
    }
  };
};

/**
 * 创建存储配置
 * @param {string} type - 文件类型
 * @returns {Object} 存储配置
 */
const createStorage = (type) => {
  return multer.diskStorage({
    destination: (req, file, cb) => {
      const dir = getStorageDir(type);
      cb(null, dir);
    },
    filename: (req, file, cb) => {
      const uniqueName = generateUniqueFileName(file.originalname);
      cb(null, uniqueName);
    }
  });
};

/**
 * 创建上传中间件
 * @param {Object} options - 配置选项
 * @returns {Function} 上传中间件
 */
const createUploadMiddleware = (options = {}) => {
  const {
    type = 'image',
    maxSize = 5 * 1024 * 1024, // 5MB
    maxFiles = 1,
    fieldName = 'file'
  } = options;
  
  const upload = multer({
    storage: createStorage(type),
    fileFilter: createFileFilter(type),
    limits: {
      fileSize: maxSize,
      files: maxFiles
    }
  });
  
  return (req, res, next) => {
    const uploadHandler = maxFiles === 1 ? upload.single(fieldName) : upload.array(fieldName, maxFiles);
    
    uploadHandler(req, res, (err) => {
      if (err) {
        logError(err, {
          type: 'file_upload_error',
          userId: req.user?.id,
          fieldName,
          maxSize,
          maxFiles
        });
        
        if (err instanceof multer.MulterError) {
          if (err.code === 'LIMIT_FILE_SIZE') {
            return next(ErrorTypes.FILE_TOO_LARGE(`文件大小不能超过 ${Math.round(maxSize / 1024 / 1024)}MB`));
          } else if (err.code === 'LIMIT_FILE_COUNT') {
            return next(ErrorTypes.FILE_UPLOAD_ERROR(`文件数量不能超过 ${maxFiles} 个`));
          } else if (err.code === 'LIMIT_UNEXPECTED_FILE') {
            return next(ErrorTypes.UNSUPPORTED_FILE_TYPE('不支持的文件字段'));
          }
        }
        
        return next(err);
      }
      
      // 记录上传成功日志
      if (req.file || req.files) {
        const files = req.files || [req.file];
        logSystemEvent('file_uploaded', {
          userId: req.user?.id,
          fileCount: files.length,
          files: files.map(f => ({
            originalName: f.originalname,
            filename: f.filename,
            size: f.size,
            mimetype: f.mimetype
          }))
        });
      }
      
      next();
    });
  };
};

/**
 * 图片处理中间件
 * @param {Object} options - 处理选项
 * @returns {Function} 处理中间件
 */
const processImage = (options = {}) => {
  return async (req, res, next) => {
    try {
      if (!req.file && !req.files) {
        return next();
      }
      
      const files = req.files || [req.file];
      const processedFiles = [];
      
      for (const file of files) {
        // 只处理图片文件
        if (!file.mimetype.startsWith('image/')) {
          processedFiles.push(file);
          continue;
        }
        
        const {
          width = null,
          height = null,
          quality = 80,
          format = 'jpeg',
          thumbnail = false,
          thumbnailSize = 200
        } = options;
        
        const inputPath = file.path;
        const outputPath = inputPath.replace(path.extname(inputPath), `.${format}`);
        
        let sharpInstance = sharp(inputPath);
        
        // 调整尺寸
        if (width || height) {
          sharpInstance = sharpInstance.resize(width, height, {
            fit: 'inside',
            withoutEnlargement: true
          });
        }
        
        // 设置质量和格式
        if (format === 'jpeg') {
          sharpInstance = sharpInstance.jpeg({ quality });
        } else if (format === 'png') {
          sharpInstance = sharpInstance.png({ quality });
        } else if (format === 'webp') {
          sharpInstance = sharpInstance.webp({ quality });
        }
        
        // 保存处理后的图片
        await sharpInstance.toFile(outputPath);
        
        // 删除原始文件（如果格式不同）
        if (inputPath !== outputPath) {
          fs.unlinkSync(inputPath);
        }
        
        // 更新文件信息
        file.path = outputPath;
        file.filename = path.basename(outputPath);
        
        // 生成缩略图
        if (thumbnail) {
          const thumbnailPath = outputPath.replace(
            path.extname(outputPath),
            `_thumb${path.extname(outputPath)}`
          );
          
          await sharp(outputPath)
            .resize(thumbnailSize, thumbnailSize, {
              fit: 'cover',
              position: 'center'
            })
            .jpeg({ quality: 70 })
            .toFile(thumbnailPath);
          
          file.thumbnail = path.basename(thumbnailPath);
        }
        
        processedFiles.push(file);
      }
      
      // 更新请求对象
      if (req.files) {
        req.files = processedFiles;
      } else {
        req.file = processedFiles[0];
      }
      
      next();
    } catch (error) {
      logError(error, {
        type: 'image_processing_error',
        userId: req.user?.id,
        options
      });
      next(ErrorTypes.FILE_UPLOAD_ERROR('图片处理失败'));
    }
  };
};

/**
 * 删除文件
 * @param {string} filePath - 文件路径
 * @returns {Promise<boolean>} 删除结果
 */
const deleteFile = async (filePath) => {
  try {
    const fullPath = path.isAbsolute(filePath) ? filePath : path.join(uploadDir, filePath);
    
    if (fs.existsSync(fullPath)) {
      fs.unlinkSync(fullPath);
      
      // 同时删除缩略图
      const thumbnailPath = fullPath.replace(
        path.extname(fullPath),
        `_thumb${path.extname(fullPath)}`
      );
      if (fs.existsSync(thumbnailPath)) {
        fs.unlinkSync(thumbnailPath);
      }
      
      logSystemEvent('file_deleted', { filePath: fullPath });
      return true;
    }
    
    return false;
  } catch (error) {
    logError(error, { type: 'file_deletion_error', filePath });
    return false;
  }
};

/**
 * 获取文件信息
 * @param {string} filePath - 文件路径
 * @returns {Object|null} 文件信息
 */
const getFileInfo = (filePath) => {
  try {
    const fullPath = path.isAbsolute(filePath) ? filePath : path.join(uploadDir, filePath);
    
    if (!fs.existsSync(fullPath)) {
      return null;
    }
    
    const stats = fs.statSync(fullPath);
    const ext = path.extname(fullPath).toLowerCase();
    
    return {
      path: filePath,
      size: stats.size,
      created: stats.birthtime,
      modified: stats.mtime,
      extension: ext,
      isImage: ['.jpg', '.jpeg', '.png', '.gif', '.webp'].includes(ext)
    };
  } catch (error) {
    logError(error, { type: 'file_info_error', filePath });
    return null;
  }
};

/**
 * 清理临时文件
 * @param {number} maxAge - 最大存在时间（毫秒）
 */
const cleanupTempFiles = (maxAge = 24 * 60 * 60 * 1000) => {
  const tempDir = path.join(uploadDir, 'temp');
  
  if (!fs.existsSync(tempDir)) {
    return;
  }
  
  fs.readdir(tempDir, (err, files) => {
    if (err) {
      logError(err, { type: 'temp_cleanup_error' });
      return;
    }
    
    const now = Date.now();
    
    files.forEach(file => {
      const filePath = path.join(tempDir, file);
      fs.stat(filePath, (err, stats) => {
        if (err) return;
        
        if (now - stats.mtime.getTime() > maxAge) {
          fs.unlink(filePath, (err) => {
            if (err) {
              logError(err, { type: 'temp_file_deletion_error', filePath });
            } else {
              logSystemEvent('temp_file_cleaned', { filePath });
            }
          });
        }
      });
    });
  });
};

// 每小时清理一次临时文件
setInterval(cleanupTempFiles, 60 * 60 * 1000);

/**
 * 预定义的上传中间件
 */
const uploadMiddlewares = {
  // 头像上传
  avatar: createUploadMiddleware({
    type: 'avatar',
    maxSize: 2 * 1024 * 1024, // 2MB
    maxFiles: 1,
    fieldName: 'avatar'
  }),
  
  // 动物图片上传
  animalImages: createUploadMiddleware({
    type: 'animal',
    maxSize: 5 * 1024 * 1024, // 5MB
    maxFiles: 5,
    fieldName: 'images'
  }),
  
  // 旅行图片上传
  travelImages: createUploadMiddleware({
    type: 'travel',
    maxSize: 5 * 1024 * 1024, // 5MB
    maxFiles: 10,
    fieldName: 'images'
  }),
  
  // 文档上传
  documents: createUploadMiddleware({
    type: 'document',
    maxSize: 10 * 1024 * 1024, // 10MB
    maxFiles: 3,
    fieldName: 'documents'
  })
};

/**
 * 预定义的图片处理中间件
 */
const imageProcessors = {
  // 头像处理
  avatar: processImage({
    width: 300,
    height: 300,
    quality: 85,
    format: 'jpeg',
    thumbnail: true,
    thumbnailSize: 100
  }),
  
  // 动物图片处理
  animal: processImage({
    width: 800,
    height: 600,
    quality: 80,
    format: 'jpeg',
    thumbnail: true,
    thumbnailSize: 200
  }),
  
  // 旅行图片处理
  travel: processImage({
    width: 1200,
    height: 800,
    quality: 80,
    format: 'jpeg',
    thumbnail: true,
    thumbnailSize: 300
  })
};

module.exports = {
  createUploadMiddleware,
  processImage,
  deleteFile,
  getFileInfo,
  cleanupTempFiles,
  uploadMiddlewares,
  imageProcessors,
  generateUniqueFileName,
  getStorageDir
};