const OSS = require('ali-oss')
const fs = require('fs')
const config = require('../../config/config.js');
const uuid = require('node-uuid')
const logs = require('../middleware/logProxy')

/**
 * OSS 文件上传服务
 * 统一管理文件上传、存储路径、文件类型等
 */
class OSSToolService {
  constructor() {
    const { accessKeyId, accessKeySecret, bucket, region, timeout } = config.oos;
    // 设置超时时间：默认30分钟（1800000ms），适用于大文件上传
    // 可以从配置文件读取，如果没有配置则使用默认值
    this.client = new OSS({
      region,
      accessKeyId,
      accessKeySecret,
      bucket,
      timeout: timeout || 30 * 60 * 1000, // 30分钟超时（1800000ms）
    })

 
    // 基础存储路径前缀
    this.basePrefix = 'front/work'
    
    // 文件类型映射
    this.fileTypeMap = {
      // 图片类型
      'image/jpeg': 'jpg',
      'image/jpg': 'jpg',
      'image/png': 'png',
      'image/gif': 'gif',
      'image/webp': 'webp',
      'image/svg+xml': 'svg',
      
      // 视频类型
      'video/mp4': 'mp4',
      'video/avi': 'avi',
      'video/mov': 'mov',
      'video/wmv': 'wmv',
      'video/flv': 'flv',
      'video/webm': 'webm',
      'video/mkv': 'mkv',
      
      // 音频类型
      'audio/mp3': 'mp3',
      'audio/wav': 'wav',
      'audio/aac': 'aac',
      'audio/ogg': 'ogg',
      'audio/flac': 'flac',
      
      // 文档类型
      'application/pdf': 'pdf',
      'application/msword': 'doc',
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
      'application/vnd.ms-excel': 'xls',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
      'application/vnd.ms-powerpoint': 'ppt',
      'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'pptx',
      'text/plain': 'txt',
      'text/html': 'html',
      'text/css': 'css',
      'application/javascript': 'js',
      'application/json': 'json'
    }
  }

  /**
   * 获取文件后缀名
   * @param {Object} file - 文件对象（兼容 formidable 格式）
   * @returns {string} 文件后缀名
   */
  getFileSuffix(file) {
    // 优先使用 MIME 类型判断（兼容 type 和 mimetype）
    const mimeType = file.mimetype || file.type
    if (mimeType && this.fileTypeMap[mimeType]) {
      return this.fileTypeMap[mimeType]
    }
    
    // 备用方案：从文件名获取（兼容 originalFilename 和 name）
    const fileName = file.originalFilename || file.name
    if (fileName) {
      const lastIndex = fileName.lastIndexOf('.')
      if (lastIndex > -1) {
        return fileName.substring(lastIndex + 1).toLowerCase()
      }
    }
    
    return 'bin'
  }

  /**
   * 获取文件存储路径
   * @param {Object} file - 文件对象（兼容 formidable 格式）
   * @param {string} category - 存储分类
   * @returns {string} 完整的存储路径
   */
  getStoragePath(file, category = 'files') {
    const suffix = this.getFileSuffix(file)
    const uid = uuid.v4()
    
    // 根据文件类型确定子路径（兼容 mimetype 和 type）
    let subPath = category
    const mimeType = file.mimetype || file.type
    
    if (mimeType) {
      if (mimeType.startsWith('image/')) {
        subPath = 'images'
      } else if (mimeType.startsWith('video/')) {
        subPath = 'videos'
      } else if (mimeType.startsWith('audio/')) {
        subPath = 'audios'
      } else if (mimeType.startsWith('application/') || mimeType.startsWith('text/')) {
        subPath = 'documents'
      }
    }
    
    // 完整路径：front/ball/{subPath}/{uid}.{suffix}
    return `${this.basePrefix}/${subPath}/${uid}.${suffix}`
  }

  /**
   * 核心文件上传方法
   * @param {Object} file - 文件对象（兼容 formidable 格式）
   * @param {string} category - 存储分类
   * @returns {Object} 上传结果
   */
  async uploadFile(file, category = 'files') {
    try {
      // 兼容不同的文件对象格式（filepath 或 path）
      const filePath = file.filepath || file.path
      
      // 验证文件
      if (!file || !filePath) {
        return { success: false, error: '无效的文件对象' }
      }

      const stream = fs.createReadStream(filePath)
      const storagePath = this.getStoragePath(file, category)
      const suffix = this.getFileSuffix(file)
      
      // 设置 content-type（兼容 mimetype 和 type）
      const contentType = file.mimetype || file.type || 'application/octet-stream'
      
      // 上传到 OSS
      const result = await this.client.put(storagePath, stream, { 
        headers: { 
          'content-disposition': 'inline', 
          "content-type": contentType 
        } 
      })
      
      if (result.res.status === 200) {
        const ossPath = config.ossUrl + '/' + result.name
        
        // 上传成功后删除临时文件
        try {
          if (fs.existsSync(filePath)) {
            fs.unlinkSync(filePath)
          }
        } catch (unlinkError) {
          logs.error('删除临时文件失败:', unlinkError)
        }
        
        return { 
          success: true,
          name: result.name, 
          path: result.url, 
          ossPath,
          fileType: file.mimetype || file.type,
          fileSize: file.size,
          originalName: file.originalFilename || file.name,
          suffix: suffix,
          storagePath: storagePath
        }
      } else {
        return { success: false, error: 'OSS 上传失败' }
      }
    } catch (error) {
      logs.error('文件上传错误:', error)
      
      // 上传失败也要清理临时文件
      try {
        const filePath = file.filepath || file.path
        if (filePath && fs.existsSync(filePath)) {
          fs.unlinkSync(filePath)
        }
      } catch (unlinkError) {
        logs.error('删除临时文件失败:', unlinkError)
      }
      
      return { success: false, error: error.message }
    }
  }

  /**
   * 上传流数据
   * @param {Stream} stream - 文件流
   * @param {string} contentType - 内容类型
   * @param {string} suffix - 文件后缀
   * @returns {Object} 上传结果
   */
  async uploadStream(stream, contentType, suffix) {
    try {
      const uid = uuid.v4()
      const storagePath = `${this.basePrefix}/files/${uid}.${suffix}`
      
      const result = await this.client.put(storagePath, stream, { 
        headers: { 
          'content-disposition': 'inline', 
          "content-type": contentType 
        } 
      })
      
      if (result.res.status === 200) {
        const ossPath = config.ossUrl + result.name
        return { 
          success: true,
          name: result.name, 
          path: result.url, 
          ossPath,
          storagePath: storagePath
        }
      } else {
        return { success: false, error: 'OSS 上传失败' }
      }
    } catch (error) {
        logs.error('流上传错误:', error)
      return { success: false, error: error.message }
    }
  }

  /**
   * 删除文件
   * @param {string} filePath - 文件路径
   * @returns {Object} 删除结果
   */
  async deleteFile(filePath) {
    try {
      if (!filePath) {
        return { success: false, error: '文件路径不能为空' }
      }

      // 从完整 URL 中提取相对路径
      const relativePath = filePath.replace(config.ossUrl + '/', '')
      const result = await this.client.delete(relativePath)
      
      if (result.res.status === 204) {
        return { success: true, message: '文件删除成功' }
      } else {
        return { success: false, error: '文件删除失败' }
      }
    } catch (error) {
        logs.error('文件删除错误:', error)
      return { success: false, error: error.message }
    }
  }

  /**
   * 获取文件信息
   * @param {string} filePath - 文件路径
   * @returns {Object} 文件信息
   */
  async getFileInfo(filePath) {
    try {
      if (!filePath) {
        return { success: false, error: '文件路径不能为空' }
      }

      const relativePath = filePath.replace(config.ossUrl + '/', '')
      const result = await this.client.head(relativePath)
      
      return {
        success: true,
        size: result.res.headers['content-length'],
        type: result.res.headers['content-type'],
        lastModified: result.res.headers['last-modified'],
        etag: result.res.headers['etag']
      }
    } catch (error) {
        logs.error('获取文件信息错误:', error)
      return { success: false, error: error.message }
    }
  }

  // ==================== 便捷方法 ====================
  
  /**
   * 上传图片文件（保持向后兼容）
   * @param {Object} file - 图片文件
   * @returns {Object} 上传结果
   */
  async putImg(file) {
    return await this.uploadFile(file, 'images')
  }




  /**
   * 上传视频文件
   * @param {Object} file - 视频文件
   * @returns {Object} 上传结果
   */
  async uploadVideo(file) {
    return await this.uploadFile(file, 'videos')
  }

  /**
   * 上传音频文件
   * @param {Object} file - 音频文件
   * @returns {Object} 上传结果
   */
  async uploadAudio(file) {
    return await this.uploadFile(file, 'audios')
  }

  /**
   * 上传文档文件
   * @param {Object} file - 文档文件
   * @returns {Object} 上传结果
   */
  async uploadDocument(file) {
    return await this.uploadFile(file, 'documents')
  }
}

// 创建单例实例
const ossToolService = new OSSToolService()

// 导出实例（保持向后兼容）
module.exports = ossToolService

