import OSS from 'ali-oss';
import path from 'path';
import fs from 'fs';

interface OSSConfig {
  region: string;
  accessKeyId: string;
  accessKeySecret: string;
  bucket: string;
  endpoint?: string;
}

class OSSService {
  private client: OSS;
  private bucket: string;
  private cdnDomain?: string;

  constructor() {
    const config: OSSConfig = {
      region: process.env.OSS_REGION || 'oss-cn-hangzhou',
      accessKeyId: process.env.OSS_ACCESS_KEY_ID || '',
      accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET || '',
      bucket: process.env.OSS_BUCKET_NAME || '',
      endpoint: process.env.OSS_ENDPOINT || 'oss-cn-hangzhou.aliyuncs.com',
    };

    this.client = new OSS(config);
    this.bucket = config.bucket;
    this.cdnDomain = process.env.OSS_CDN_DOMAIN;
  }

  /**
   * 上传文件到 OSS
   * @param localPath 本地文件路径
   * @param objectKey OSS 对象键（路径）
   * @returns OSS 文件 URL
   */
  async uploadFile(localPath: string, objectKey: string): Promise<string> {
    try {
      // 确保 objectKey 格式正确
      const normalizedKey = objectKey.replace(/\\/g, '/').replace(/^\/+/, '');
      
      const result = await this.client.put(normalizedKey, localPath, {
        headers: {
          'Content-Type': this.getContentType(normalizedKey),
        },
      });

      console.log(`[OSS] 文件上传成功: ${normalizedKey}`);
      
      // 返回文件 URL
      return this.getFileUrl(normalizedKey);
    } catch (error) {
      console.error('[OSS] 文件上传失败:', error);
      throw new Error(`OSS 上传失败: ${(error as Error).message}`);
    }
  }

  /**
   * 上传 Buffer 到 OSS
   * @param buffer 文件 Buffer
   * @param objectKey OSS 对象键
   * @param contentType 内容类型
   * @returns OSS 文件 URL
   */
  async uploadBuffer(buffer: Buffer, objectKey: string, contentType?: string): Promise<string> {
    try {
      const normalizedKey = objectKey.replace(/\\/g, '/').replace(/^\/+/, '');
      
      const result = await this.client.put(normalizedKey, buffer, {
        headers: {
          'Content-Type': contentType || this.getContentType(normalizedKey),
        },
      });

      console.log(`[OSS] Buffer 上传成功: ${normalizedKey}`);
      
      return this.getFileUrl(normalizedKey);
    } catch (error) {
      console.error('[OSS] Buffer 上传失败:', error);
      throw new Error(`OSS Buffer 上传失败: ${(error as Error).message}`);
    }
  }

  /**
   * 上传音频文件
   * @param localPath 本地音频文件路径
   * @param audioId 音频 ID
   * @returns OSS 音频 URL
   */
  async uploadAudio(localPath: string, audioId: string): Promise<string> {
    const objectKey = `audio/${audioId}/${path.basename(localPath)}`;
    return this.uploadFile(localPath, objectKey);
  }

  /**
   * 上传视频文件
   * @param localPath 本地视频文件路径
   * @param videoId 视频 ID
   * @returns OSS 视频 URL
   */
  async uploadVideo(localPath: string, videoId: string): Promise<string> {
    const objectKey = `video/${videoId}/${path.basename(localPath)}`;
    return this.uploadFile(localPath, objectKey);
  }

  /**
   * 上传封面图片
   * @param localPath 本地图片路径
   * @param bookId 书籍 ID
   * @returns OSS 图片 URL
   */
  async uploadCover(localPath: string, bookId: string | number): Promise<string> {
    const ext = path.extname(localPath);
    const objectKey = `cover/${bookId}/cover${ext}`;
    return this.uploadFile(localPath, objectKey);
  }

  /**
   * 删除文件
   * @param objectKey OSS 对象键
   */
  async deleteFile(objectKey: string): Promise<void> {
    try {
      const normalizedKey = objectKey.replace(/\\/g, '/').replace(/^\/+/, '');
      await this.client.delete(normalizedKey);
      console.log(`[OSS] 文件删除成功: ${normalizedKey}`);
    } catch (error) {
      console.error('[OSS] 文件删除失败:', error);
      throw new Error(`OSS 删除失败: ${(error as Error).message}`);
    }
  }

  /**
   * 删除整个目录
   * @param prefix 目录前缀
   */
  async deleteDirectory(prefix: string): Promise<void> {
    try {
      const normalizedPrefix = prefix.replace(/\\/g, '/').replace(/^\/+/, '').replace(/\/+$/, '') + '/';
      
      // 列出目录下所有文件
      const result = await this.client.list({
        prefix: normalizedPrefix,
        'max-keys': 1000,
      });

      // 批量删除
      if (result.objects && result.objects.length > 0) {
        const keys = result.objects.map(obj => obj.name);
        await this.client.deleteMulti(keys);
        console.log(`[OSS] 目录删除成功: ${normalizedPrefix} (${keys.length} 个文件)`);
      }
    } catch (error) {
      console.error('[OSS] 目录删除失败:', error);
      throw new Error(`OSS 目录删除失败: ${(error as Error).message}`);
    }
  }

  /**
   * 获取文件签名 URL（用于私有 bucket）
   * @param objectKey OSS 对象键
   * @param expires 过期时间（秒），默认 3600 秒
   * @returns 签名 URL
   */
  async getSignedUrl(objectKey: string, expires: number = 3600): Promise<string> {
    try {
      const normalizedKey = objectKey.replace(/\\/g, '/').replace(/^\/+/, '');
      const url = this.client.signatureUrl(normalizedKey, {
        expires,
      });
      return url;
    } catch (error) {
      console.error('[OSS] 获取签名 URL 失败:', error);
      throw new Error(`获取签名 URL 失败: ${(error as Error).message}`);
    }
  }

  /**
   * 下载文件
   * @param objectKey OSS 对象键
   * @returns 文件 Buffer
   */
  async downloadFile(objectKey: string): Promise<Buffer> {
    try {
      const normalizedKey = objectKey.replace(/\\/g, '/').replace(/^\/+/, '');
      const result = await this.client.get(normalizedKey);
      return result.content;
    } catch (error) {
      console.error('[OSS] 文件下载失败:', error);
      throw new Error(`OSS 文件下载失败: ${(error as Error).message}`);
    }
  }

  /**
   * 获取文件 URL
   * @param objectKey OSS 对象键
   * @returns 文件 URL
   */
  getFileUrl(objectKey: string): string {
    const normalizedKey = objectKey.replace(/\\/g, '/').replace(/^\/+/, '');
    
    // 如果配置了 CDN 域名，使用 CDN
    if (this.cdnDomain) {
      return `${this.cdnDomain}/${normalizedKey}`;
    }
    
    // 否则使用 OSS 默认域名
    return `https://${this.bucket}.${process.env.OSS_ENDPOINT}/${normalizedKey}`;
  }

  /**
   * 根据文件扩展名获取 Content-Type
   * @param filename 文件名
   * @returns Content-Type
   */
  private getContentType(filename: string): string {
    const ext = path.extname(filename).toLowerCase();
    const contentTypes: Record<string, string> = {
      '.mp3': 'audio/mpeg',
      '.wav': 'audio/wav',
      '.aac': 'audio/aac',
      '.mp4': 'video/mp4',
      '.avi': 'video/avi',
      '.mov': 'video/quicktime',
      '.jpg': 'image/jpeg',
      '.jpeg': 'image/jpeg',
      '.png': 'image/png',
      '.gif': 'image/gif',
      '.webp': 'image/webp',
      '.json': 'application/json',
      '.txt': 'text/plain',
    };
    
    return contentTypes[ext] || 'application/octet-stream';
  }

  /**
   * 测试 OSS 连接
   */
  async testConnection(): Promise<boolean> {
    try {
      await this.client.getBucketInfo(this.bucket);
      console.log('[OSS] 连接测试成功');
      return true;
    } catch (error) {
      console.error('[OSS] 连接测试失败:', error);
      return false;
    }
  }
}

// 导出单例
export const ossService = new OSSService();
export default ossService;
