const Base = require('../base.js');
const COS = require('cos-nodejs-sdk-v5');
const fs = require('fs');
const path = require('path');
const cosConfig = require('../../config/cos.js');

module.exports = class extends Base {
  /**
   * 文件上传
   * POST /admin/upload
   */
  async indexAction() {
    // 辅助函数：延迟
    const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

    // 获取文件（处理 ThinkJS 文件获取延迟问题）
    let file = this.file('file');
    let filePath = file ? file.path : '';

    if (!filePath) {
      await sleep(1000);
      file = this.file('file');
      filePath = file ? file.path : '';
      if (!filePath) {
        await sleep(1000);
        file = this.file('file');
        filePath = file ? file.path : '';
        if (!filePath) {
          return this.fail('请选择要上传的文件');
        }
      }
    }

    try {
      // 获取文件信息
      const originalName = file.name;
      const fileSize = file.size;
      const mimeType = file.type;

      // 验证文件类型和大小
      const validation = this.validateFile(mimeType, fileSize);
      if (!validation.valid) {
        // 删除临时文件
        if (fs.existsSync(filePath)) {
          fs.unlinkSync(filePath);
        }
        return this.fail(validation.message);
      }

      // 生成存储路径（按日期分类）
      const now = new Date();
      const year = now.getFullYear();
      const month = String(now.getMonth() + 1).padStart(2, '0');
      const day = String(now.getDate()).padStart(2, '0');
      const dateFolder = `${year}/${month}/${day}`;

      // 生成文件名（保留原文件名，添加时间戳避免重复）
      const timestamp = Date.now();
      const ext = path.extname(originalName);
      const baseName = path.basename(originalName, ext);
      const fileName = `${baseName}_${timestamp}${ext}`;
      const cosKey = `uploads/${dateFolder}/${fileName}`;

      // 如果是图片，进行压缩处理
      let uploadFilePath = filePath;
      let actualFileSize = fileSize;

      if (this.isImage(mimeType)) {
        // 检查文件大小是否需要压缩
        if (fileSize < cosConfig.imageCompress.minSize) {
          think.logger.info(`图片小于 ${cosConfig.imageCompress.minSize / 1024}KB，跳过压缩`);
        } else {
          try {
            const compressResult = await this.compressImage(filePath, mimeType);
            // 比较压缩后的文件大小，如果压缩后更大则使用原图
            if (compressResult.compressedPath && compressResult.compressedSize < fileSize) {
              uploadFilePath = compressResult.compressedPath;
              actualFileSize = compressResult.compressedSize;
              think.logger.info(`图片压缩成功: ${fileSize} -> ${compressResult.compressedSize} (节省 ${((1 - compressResult.compressedSize / fileSize) * 100).toFixed(2)}%)`);
            } else {
              think.logger.info('压缩后文件更大，使用原图上传');
              // 删除压缩后的文件
              if (compressResult.compressedPath && fs.existsSync(compressResult.compressedPath)) {
                try {
                  fs.unlinkSync(compressResult.compressedPath);
                } catch (e) {
                  think.logger.warn('删除压缩文件失败:', e.message);
                }
              }
            }
          } catch (compressError) {
            think.logger.warn('图片压缩失败，使用原图上传:', compressError);
            // 压缩失败时使用原图
          }
        }
      }

      // 初始化 COS 客户端
      const cos = new COS({
        SecretId: cosConfig.secretId,
        SecretKey: cosConfig.secretKey
      });

      // 上传文件到 COS
      const uploadResult = await new Promise((resolve, reject) => {
        cos.putObject({
          Bucket: cosConfig.bucket,
          Region: cosConfig.region,
          Key: cosKey,
          Body: fs.createReadStream(uploadFilePath),
          ContentType: mimeType,
          onProgress: (progressData) => {
            // 可以在这里处理上传进度
          }
        }, (err, data) => {
          if (err) {
            reject(err);
          } else {
            resolve(data);
          }
        });
      });

      // 清理临时文件（延迟删除，避免 Windows 文件句柄未释放问题）
      setTimeout(() => {
        try {
          if (fs.existsSync(filePath)) {
            fs.unlinkSync(filePath);
          }
        } catch (e) {
          think.logger.warn('删除临时文件失败:', e.message);
        }
        try {
          if (uploadFilePath !== filePath && fs.existsSync(uploadFilePath)) {
            fs.unlinkSync(uploadFilePath);
          }
        } catch (e) {
          think.logger.warn('删除压缩文件失败:', e.message);
        }
      }, 1000);

      // 返回结果
      if (uploadResult.statusCode === 200) {
        const bucketUrl = `https://${uploadResult.Location}`;
        const cdnUrl = bucketUrl.replace(cosConfig.bucketUrl, cosConfig.cdnUrl);

        return this.success({
          url: cdnUrl,
          name: originalName,
          bucket_url: bucketUrl,
          file_name: originalName,
          file_size: actualFileSize,
          mime_type: mimeType
        });
      } else {
        return this.fail('文件上传失败');
      }
    } catch (error) {
      think.logger.error('文件上传失败:', error);
      // 清理临时文件
      if (file && file.path && fs.existsSync(file.path)) {
        try {
          fs.unlinkSync(file.path);
        } catch (cleanError) {
          think.logger.error('清理临时文件失败:', cleanError);
        }
      }
      return this.fail('文件上传失败: ' + error.message);
    }
  }

  /**
   * 验证文件类型和大小
   */
  validateFile(mimeType, fileSize) {
    const allAllowedTypes = [
      ...cosConfig.allowedImageTypes,
      ...cosConfig.allowedDocTypes,
      ...cosConfig.allowedVideoTypes
    ];

    // 验证文件类型
    if (!allAllowedTypes.includes(mimeType)) {
      return {
        valid: false,
        message: '不支持的文件类型'
      };
    }

    // 验证文件大小
    let maxSize = 0;
    if (cosConfig.allowedImageTypes.includes(mimeType)) {
      maxSize = cosConfig.maxImageSize;
    } else if (cosConfig.allowedDocTypes.includes(mimeType)) {
      maxSize = cosConfig.maxDocSize;
    } else if (cosConfig.allowedVideoTypes.includes(mimeType)) {
      maxSize = cosConfig.maxVideoSize;
    }

    if (fileSize > maxSize) {
      const maxSizeMB = (maxSize / 1024 / 1024).toFixed(0);
      return {
        valid: false,
        message: `文件大小不能超过 ${maxSizeMB}MB`
      };
    }

    return { valid: true };
  }

  /**
   * 判断是否为图片
   */
  isImage(mimeType) {
    return cosConfig.allowedImageTypes.includes(mimeType);
  }

  /**
   * 压缩图片
   * 返回压缩后的文件路径和文件大小
   */
  async compressImage(filePath, mimeType) {
    // 尝试加载 sharp，如果没有安装则跳过压缩
    let sharp;
    try {
      sharp = require('sharp');
    } catch (e) {
      think.logger.warn('sharp 模块未安装，跳过图片压缩');
      return { compressedPath: null, compressedSize: 0 };
    }

    const compressedPath = filePath + '_compressed';
    const { quality, maxWidth, maxHeight } = cosConfig.imageCompress;

    try {
      const image = sharp(filePath);
      const metadata = await image.metadata();

      // 计算缩放尺寸
      let resizeOptions = {};
      if (metadata.width > maxWidth || metadata.height > maxHeight) {
        resizeOptions = {
          width: maxWidth,
          height: maxHeight,
          fit: 'inside',
          withoutEnlargement: true
        };
      }

      // 根据图片类型选择压缩格式
      let outputOptions = {};
      if (mimeType === 'image/jpeg' || mimeType === 'image/jpg') {
        outputOptions = { quality };
        await image.resize(resizeOptions).jpeg(outputOptions).toFile(compressedPath);
      } else if (mimeType === 'image/png') {
        outputOptions = { quality, compressionLevel: 9 };
        await image.resize(resizeOptions).png(outputOptions).toFile(compressedPath);
      } else if (mimeType === 'image/webp') {
        outputOptions = { quality };
        await image.resize(resizeOptions).webp(outputOptions).toFile(compressedPath);
      } else {
        // 其他格式不压缩
        return {
          compressedPath: null,
          compressedSize: 0
        };
      }

      // 获取压缩后的文件大小
      const stats = fs.statSync(compressedPath);
      const compressedSize = stats.size;

      return {
        compressedPath,
        compressedSize
      };
    } catch (error) {
      think.logger.error('图片压缩失败:', error);
      throw error;
    }
  }

  /**
   * 获取上传配置信息
   * GET /admin/upload/config
   */
  async configAction() {
    try {
      return this.success({
        allowedTypes: {
          images: cosConfig.allowedImageTypes,
          documents: cosConfig.allowedDocTypes,
          videos: cosConfig.allowedVideoTypes
        },
        maxSize: {
          image: cosConfig.maxImageSize,
          document: cosConfig.maxDocSize,
          video: cosConfig.maxVideoSize
        }
      });
    } catch (error) {
      think.logger.error('获取上传配置失败:', error);
      return this.fail('获取上传配置失败');
    }
  }
};
