import { Injectable, OnModuleInit, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as Minio from 'minio';

@Injectable()
export class MinioStorageAdapter implements OnModuleInit {
  private readonly logger = new Logger(MinioStorageAdapter.name);
  private client: Minio.Client;
  private bucketName: string;

  constructor(private readonly configService: ConfigService) {
    this.client = new Minio.Client({
      endPoint: this.configService.get('MINIO_ENDPOINT', 'minio'),
      port: this.configService.get<number>('MINIO_PORT', 9000),
      useSSL: this.configService.get('MINIO_USE_SSL', 'false') === 'true',
      accessKey: this.configService.get('MINIO_ACCESS_KEY', 'minioadmin'),
      secretKey: this.configService.get('MINIO_SECRET_KEY', 'minioadmin123'),
    });
    this.bucketName = this.configService.get('MINIO_BUCKET', 'iconsulting');
  }

  async onModuleInit() {
    try {
      const exists = await this.client.bucketExists(this.bucketName);
      if (!exists) {
        await this.client.makeBucket(this.bucketName);
        this.logger.log(`Bucket ${this.bucketName} created successfully`);
      } else {
        this.logger.log(`Bucket ${this.bucketName} already exists`);
      }
    } catch (error) {
      this.logger.error(`Failed to initialize MinIO bucket: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  /**
   * 上传文件到 MinIO
   */
  async uploadFile(
    objectName: string,
    buffer: Buffer,
    contentType: string,
    metadata?: Record<string, string>,
  ): Promise<string> {
    await this.client.putObject(
      this.bucketName,
      objectName,
      buffer,
      buffer.length,
      {
        'Content-Type': contentType,
        ...metadata,
      },
    );
    return objectName;
  }

  /**
   * 获取预签名下载 URL
   */
  async getPresignedUrl(
    objectName: string,
    expirySeconds: number = 3600,
  ): Promise<string> {
    return this.client.presignedGetObject(
      this.bucketName,
      objectName,
      expirySeconds,
    );
  }

  /**
   * 获取预签名上传 URL
   */
  async getPresignedPutUrl(
    objectName: string,
    expirySeconds: number = 3600,
  ): Promise<string> {
    return this.client.presignedPutObject(
      this.bucketName,
      objectName,
      expirySeconds,
    );
  }

  /**
   * 删除文件
   */
  async deleteFile(objectName: string): Promise<void> {
    await this.client.removeObject(this.bucketName, objectName);
  }

  /**
   * 获取文件信息
   */
  async getFileInfo(objectName: string): Promise<Minio.BucketItemStat> {
    return this.client.statObject(this.bucketName, objectName);
  }

  /**
   * 下载文件为 Buffer
   */
  async downloadFile(objectName: string): Promise<Buffer> {
    const stream = await this.client.getObject(this.bucketName, objectName);
    const chunks: Buffer[] = [];

    return new Promise((resolve, reject) => {
      stream.on('data', (chunk: Buffer) => chunks.push(chunk));
      stream.on('error', reject);
      stream.on('end', () => resolve(Buffer.concat(chunks)));
    });
  }

  /**
   * 列出指定前缀的文件
   */
  async listFiles(prefix: string): Promise<Minio.BucketItem[]> {
    const objects: Minio.BucketItem[] = [];
    const stream = this.client.listObjects(this.bucketName, prefix, true);

    return new Promise((resolve, reject) => {
      stream.on('data', (obj: Minio.BucketItem) => objects.push(obj));
      stream.on('error', reject);
      stream.on('end', () => resolve(objects));
    });
  }

  /**
   * 复制文件
   */
  async copyFile(sourceObject: string, destObject: string): Promise<void> {
    const conds = new Minio.CopyConditions();
    await this.client.copyObject(
      this.bucketName,
      destObject,
      `/${this.bucketName}/${sourceObject}`,
      conds,
    );
  }
}
