import { GenericCrudService } from '@/server/utils/generic-crud.service';
import { DataSource } from 'typeorm';
import { File } from './file.entity';
import { MinioService } from './minio.service';
import { v4 as uuidv4 } from 'uuid';
import { logger } from '@/server/utils/logger';

export class FileService extends GenericCrudService<File> {
  private readonly minioService: MinioService;

  constructor(dataSource: DataSource) {
    super(dataSource, File);
    this.minioService = new MinioService();
  }

  /**
   * 创建文件记录并生成预签名上传URL
   */
  async createFile(data: Partial<File>) {
    try {
      // 生成唯一文件存储路径
      const fileKey = `${data.uploadUserId}/${uuidv4()}-${data.name}`;
      // 生成MinIO上传策略
      const uploadPolicy = await this.minioService.generateUploadPolicy(fileKey);

      
      // 准备文件记录数据
      const fileData = {
        ...data,
        path: fileKey,
        uploadTime: new Date(),
        createdAt: new Date(),
        updatedAt: new Date()
      };
      
      // 保存文件记录到数据库
      const savedFile = await this.create(fileData as File);
      
      // 返回文件记录和上传策略
      return {
        file: savedFile,
        uploadPolicy
      };
    } catch (error) {
      logger.error('Failed to create file:', error);
      throw new Error('文件创建失败');
    }
  }

  /**
   * 删除文件记录及对应的MinIO文件
   */
  async deleteFile(id: number) {
    // 获取文件记录
    const file = await this.getById(id);
    if (!file) {
      throw new Error('文件不存在');
    }

    try {
      // 验证文件是否存在于MinIO
      const fileExists = await this.minioService.objectExists(this.minioService.bucketName, file.path);
      if (!fileExists) {
        logger.error(`File not found in MinIO: ${this.minioService.bucketName}/${file.path}`);
        // 仍然继续删除数据库记录，但记录警告日志
      } else {
        // 从MinIO删除文件
        await this.minioService.deleteObject(this.minioService.bucketName, file.path);
      }

      // 从数据库删除记录
      await this.delete(id);

      return true;
    } catch (error) {
      logger.error('Failed to delete file:', error);
      throw new Error('文件删除失败');
    }
  }

  /**
   * 获取文件访问URL
   */
  async getFileUrl(id: number) {
    const file = await this.getById(id);
    if (!file) {
      throw new Error('文件不存在');
    }
    
    return this.minioService.getPresignedFileUrl(this.minioService.bucketName, file.path);
  }

  /**
   * 获取文件下载URL（带Content-Disposition头）
   */
  async getFileDownloadUrl(id: number) {
    const file = await this.getById(id);
    if (!file) {
      throw new Error('文件不存在');
    }
    
    const url = await this.minioService.getPresignedFileDownloadUrl(
      this.minioService.bucketName,
      file.path,
      file.name
    );
    
    return {
      url,
      filename: file.name
    };
  }

  /**
   * 创建多部分上传策略
   */
  async createMultipartUploadPolicy(data: Partial<File>, partCount: number) {
    try {
      // 生成唯一文件存储路径
      const fileKey = `${data.uploadUserId}/${uuidv4()}-${data.name}`;
      
      // 初始化多部分上传
      const uploadId = await this.minioService.createMultipartUpload(
        this.minioService.bucketName,
        fileKey
      );
      
      // 生成各部分上传URL
      const uploadUrls = await this.minioService.generateMultipartUploadUrls(
        this.minioService.bucketName,
        fileKey,
        uploadId,
        partCount
      );
      
      // 准备文件记录数据
      const fileData = {
        ...data,
        path: fileKey,
        uploadTime: new Date(),
        createdAt: new Date(),
        updatedAt: new Date()
      };
      
      // 保存文件记录到数据库
      const savedFile = await this.create(fileData as File);
      
      // 返回文件记录和上传策略
      return {
        file: savedFile,
        uploadId,
        uploadUrls,
        bucket: this.minioService.bucketName,
        key: fileKey
      };
    } catch (error) {
      logger.error('Failed to create multipart upload policy:', error);
      throw new Error('创建多部分上传策略失败');
    }
  }

  /**
   * 完成分片上传
   */
  async completeMultipartUpload(data: {
    uploadId: string;
    bucket: string;
    key: string;
    parts: Array<{ partNumber: number; etag: string }>;
  }) {
    logger.db('Starting multipart upload completion:', {
      uploadId: data.uploadId,
      bucket: data.bucket,
      key: data.key,
      partsCount: data.parts.length
    });

    // 查找文件记录
    const file = await this.repository.findOneBy({ path: data.key });
    if (!file) {
      throw new Error('文件记录不存在');
    }

    try {
      // 完成MinIO分片上传 - 注意格式转换
      const result = await this.minioService.completeMultipartUpload(
        data.bucket,
        data.key,
        data.uploadId,
        data.parts.map(part => ({ PartNumber: part.partNumber, ETag: part.etag }))
      );

      // 更新文件大小等信息
      file.size = result.size;
      file.updatedAt = new Date();
      await this.repository.save(file);

      // 生成文件访问URL
      const url = this.minioService.getFileUrl(data.bucket, data.key);

      logger.db('Multipart upload completed successfully:', {
        fileId: file.id,
        size: result.size,
        key: data.key
      });

      return {
        fileId: file.id,
        url,
        key: data.key,
        size: result.size
      };
    } catch (error) {
      logger.error('Failed to complete multipart upload:', error);
      throw new Error('完成分片上传失败');
    }
  }
}