import { Injectable, Logger } from '@nestjs/common';
import * as fs from 'fs';
import * as path from 'path';
import * as archiver from 'archiver';
import { BackupTarget } from '@/domain/enums';
import {
  BackupHandler,
  BackupResult,
  ProgressCallback,
} from '@/domain/interfaces/backup-handler.interface';

@Injectable()
export class KafkaBackupHandler implements BackupHandler {
  readonly target = BackupTarget.KAFKA;
  private readonly logger = new Logger(KafkaBackupHandler.name);

  private readonly sourceDir = '/backup-source/kafka';

  async execute(outputDir: string, onProgress: ProgressCallback): Promise<BackupResult> {
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const fileName = `kafka-${timestamp}.tar.gz`;
    const filePath = path.join(outputDir, fileName);

    fs.mkdirSync(outputDir, { recursive: true });

    if (!fs.existsSync(this.sourceDir)) {
      throw new Error(`Kafka 数据目录不存在: ${this.sourceDir}`);
    }

    onProgress(0, 'Kafka 数据打包开始...');

    // 先计算总大小
    const totalSize = this.getDirSize(this.sourceDir);
    this.logger.log(`Kafka 数据目录大小: ${totalSize} bytes`);

    return new Promise<BackupResult>((resolve, reject) => {
      const output = fs.createWriteStream(filePath);
      const archive = archiver('tar', { gzip: true });

      let processedBytes = 0;
      archive.on('progress', (progress) => {
        processedBytes = progress.fs.processedBytes;
        if (totalSize > 0) {
          const percent = Math.min(99, Math.floor((processedBytes / totalSize) * 100));
          onProgress(percent, `Kafka 打包中 ${percent}%`);
        }
      });

      output.on('close', () => {
        const fileSize = archive.pointer();
        this.logger.log(`Kafka 备份完成: ${fileName}, 大小: ${fileSize} bytes`);
        onProgress(100, 'Kafka 备份完成');
        resolve({ fileName, filePath, fileSize });
      });

      archive.on('error', (err) => {
        this.logger.error(`Kafka 备份打包失败: ${err.message}`);
        reject(err);
      });

      archive.pipe(output);
      archive.directory(this.sourceDir, 'kafka');
      archive.finalize();
    });
  }

  private getDirSize(dirPath: string): number {
    let size = 0;
    try {
      const entries = fs.readdirSync(dirPath, { withFileTypes: true });
      for (const entry of entries) {
        const fullPath = path.join(dirPath, entry.name);
        if (entry.isFile()) {
          size += fs.statSync(fullPath).size;
        } else if (entry.isDirectory()) {
          size += this.getDirSize(fullPath);
        }
      }
    } catch {
      // 忽略权限错误
    }
    return size;
  }
}
