// https://github.com/vbenjs/vue-vben-admin/blob/03ceb2aac5a47d7127562f2855d41da5c58b81bf/internal/vite-config/src/plugins/archiver.ts
// http://web.archive.org/web/20250322165307/https://933331.xyz/2024/09/10/vite%E8%87%AA%E5%8A%A8%E6%89%93%E5%8C%85%E6%8F%92%E4%BB%B6/

import type { Plugin } from 'vite';

import archiver from 'archiver';
import fs from 'node:fs';
import path from 'node:path';
import { createLogger } from 'vite';

interface ArchiverOptions {
  /**
   * 是否添加时间戳到输出文件名
   * @default false
   */
  addTimestamp?: boolean;
  /**
   * 压缩格式，支持 'zip', 'tar', 'tgz'
   * @default 'zip'
   */
  format?: 'tar' | 'tgz' | 'zip';
  /**
   * 输出目录
   * @default ''
   */
  outputDir?: string;
  /**
   * 输出的文件名（不含扩展名）
   * @default 'dist'
   */
  outputFileName?: string;
  /**
   * 要打包的源目录，可以是单个目录或目录数组
   * @default 'dist'
   */
  sourceDir?: string | string[];
}

/**
 * 用于将构建输出打包成压缩文件的Vite插件
 */
export function viteArchiverPlugin(options: ArchiverOptions = {}): Plugin {
  const { addTimestamp = false, format = 'zip', outputDir = '', outputFileName = 'dist', sourceDir = 'dist' } = options;

  // 创建Vite日志记录器
  const logger = createLogger();

  return {
    apply: 'build',
    closeBundle: async () => {
      // 处理单个目录或目录数组
      const sourceDirs = Array.isArray(sourceDir) ? sourceDir : [sourceDir];
      const sourcePaths = sourceDirs.map((dir) => path.resolve(process.cwd(), dir));

      // 检查所有源目录是否存在
      const nonExistentDirs = sourcePaths.filter((dir) => !fs.existsSync(dir));
      if (nonExistentDirs.length > 0) {
        logger.error(`Source directories do not exist: ${nonExistentDirs.join(', ')}`);
        return;
      }

      logger.info(`Creating archive from: ${sourceDirs.join(', ')}`);

      // 如果输出目录不存在，则创建它
      const outputPath = path.resolve(process.cwd(), outputDir);
      if (outputDir && !fs.existsSync(outputPath)) {
        fs.mkdirSync(outputPath, { recursive: true });
      }

      // 生成文件名，可选添加时间戳
      let finalFileName = outputFileName;
      if (addTimestamp) {
        const now = new Date();
        const timestamp = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}-${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}`;
        finalFileName = `${outputFileName}-${timestamp}`;
      }

      // 根据格式确定文件扩展名
      const fileExtension = format === 'zip' ? 'zip' : (format === 'tar' ? 'tar' : 'tar.gz');
      const outputFilePath = path.join(outputPath, `${finalFileName}.${fileExtension}`);
      const output = fs.createWriteStream(outputFilePath);

      // 创建适当格式的归档器
      const archive = archiver(format === 'tgz' ? 'tar' : format, {
        gzip: format === 'tgz',
        ...(format === 'zip' ? { zlib: { level: 9 } } : {}),
      });

      // 监听所有归档数据写入完成
      output.on('close', () => {
        logger.info(`Archive created: ${outputFilePath}`);
      });

      // 错误处理
      archive.on('warning', (err) => {
        if (err.code === 'ENOENT') {
          logger.warn(`Warning during archiving: ${err.message}`);
        } else {
          logger.error(`Error during archiving: ${err.message}`);
          throw err;
        }
      });

      archive.on('error', (err) => {
        logger.error(`Fatal error during archiving: ${err.message}`);
        throw err;
      });

      // 将归档数据通过管道传输到文件
      archive.pipe(output);

      // 添加文件到归档
      for (const sourcePath of sourcePaths) {
        archive.directory(sourcePath, false);
      }

      // 完成归档
      await archive.finalize();
    },
    name: 'vite-plugin-archiver',
  };
}
