import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import babel from '@rollup/plugin-babel';
import terser from '@rollup/plugin-terser';
import { readFileSync, existsSync } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { glob } from 'glob';

// 获取当前文件所在目录的绝对路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 读取 package.json，用于获取依赖列表
const pkg = JSON.parse(readFileSync('./package.json', 'utf-8'));

/**
 * 收集所有的入口文件
 *
 * 遍历指定目录，查找所有 .js 文件作为打包入口
 * 注意：json 目录被排除，因为 JSON 文件直接复制，不作为入口处理
 *
 * @returns {Object} 入口文件对象，格式：{ 'components/Table/index.js': '/absolute/path/Table/index.js' }
 */
function getEntryFiles() {
  const entries = {};
  const baseDir = __dirname;
  const srcDir = path.join(baseDir, 'src');

  // 定义需要处理的目录（排除json，json文件直接复制不转换）
  const dirs = ['components', 'hooks', 'utils', 'regular', 'enum'];

  dirs.forEach(dir => {
    const dirPath = path.join(srcDir, dir);

    if (existsSync(dirPath)) {
      // 递归查找当前目录下所有 .js 文件
      const files = glob.sync('**/*.js', {
        cwd: dirPath,      // 在 src/xxx 目录中查找
        absolute: false    // 返回相对路径
      });

      // 为每个文件创建入口映射
      files.forEach(file => {
        // key: 保留源文件的相对路径（包括目录和文件名），如 'components/Table/index.js'
        // value: src 目录下文件的绝对路径
        const key = path.join(dir, file);
        entries[key] = path.join(srcDir, dir, file);
      });
    }
  });

  return entries;
}

/**
 * Babel 配置
 *
 * 只转换 JSX 语法，不转译 ES6+ 语法
 * 这样可以保持代码的现代性，减少构建时间
 */
const babelConfig = {
  // 将 Babel helpers 捆绑到每个文件中（避免重复引用）
  babelHelpers: 'bundled',

  // 排除 node_modules 目录，不进行处理
  exclude: 'node_modules/**',

  // 支持的文件扩展名
  extensions: ['.js', '.jsx', '.ts', '.tsx'],

  // 使用的预设和插件
  presets: [
    ['@babel/preset-react', {
      // 使用新的 JSX 转换方式，自动导入 JSX
      runtime: 'automatic'
    }]
  ],
  plugins: []
};

/**
 * 自定义插件：复制类型声明文件和样式文件
 *
 * 功能：
 * 1. 复制 .d.ts 类型声明文件
 * 2. 复制 .less/.css 等样式文件（保持原始格式）
 * 3. 复制图片文件 (.png, .jpg, .jpeg, .gif, .svg, .webp)
 * 4. 复制 .json 数据文件（保持原始格式）
 * 5. 复制 css 文件夹
 *
 * 注意：所有源文件都在 src/ 目录，构建输出到根目录
 */
const copyTypesPlugin = () => ({
  name: 'copy-types',

  // 在生成 bundle 时执行
  generateBundle() {
    const srcDir = path.join(__dirname, 'src');
    const dirs = ['components', 'hooks', 'utils', 'regular', 'enum', 'json'];
    const this$1 = this;

    // 处理每个目录
    dirs.forEach(dir => {
      const dirPath = path.join(srcDir, dir);

      if (existsSync(dirPath)) {
        // ===== 1. 复制类型声明文件 (.d.ts) =====
        const dtsFiles = glob.sync('**/*.d.ts', {
          cwd: dirPath,
          absolute: true
        });

        dtsFiles.forEach(file => {
          const relativePath = path.relative(dirPath, file);
          const content = readFileSync(file, 'utf-8');

          // 将文件添加到根目录
          this$1.emitFile({
            type: 'asset',
            fileName: path.join(dir, relativePath),
            source: content
          });
        });

        // ===== 2. 复制样式文件 (.less, .css, .scss, .sass) =====
        const styleFiles = glob.sync('**/*.{less,css,scss,sass}', {
          cwd: dirPath,
          absolute: true
        });

        styleFiles.forEach(file => {
          const relativePath = path.relative(dirPath, file);
          const content = readFileSync(file, 'utf-8');

          // 将样式文件添加到根目录，保持原始格式
          this$1.emitFile({
            type: 'asset',
            fileName: path.join(dir, relativePath),
            source: content
          });
        });

        // ===== 3. 复制图片文件 (.png, .jpg, .jpeg, .gif, .svg, .webp) =====
        const imageFiles = glob.sync('**/*.{png,jpg,jpeg,gif,svg,webp}', {
          cwd: dirPath,
          absolute: true
        });

        imageFiles.forEach(file => {
          const relativePath = path.relative(dirPath, file);
          // 读取二进制文件，明确不使用编码
          const content = readFileSync(file, null);

          // 将图片文件添加到根目录，保持二进制格式
          this$1.emitFile({
            type: 'asset',
            fileName: path.join(dir, relativePath),
            source: content
          });
        });
      }
    });

    // ===== 4. 复制 json 文件夹（保持原始格式，不转换） =====
    const jsonDir = path.join(srcDir, 'json');
    if (existsSync(jsonDir)) {
      const jsonFiles = glob.sync('**/*.json', {
        cwd: jsonDir,
        absolute: true
      });

      jsonFiles.forEach(file => {
        const relativePath = path.relative(jsonDir, file);
        const content = readFileSync(file, 'utf-8');

        // 将 JSON 文件添加到根目录
        this$1.emitFile({
          type: 'asset',
          fileName: path.join('json', relativePath),
          source: content
        });
      });
    }

    // ===== 5. 复制 css 文件夹 =====
    const cssDir = path.join(srcDir, 'css');
    if (existsSync(cssDir)) {
      const cssFiles = glob.sync('**/*', {
        cwd: cssDir,
        absolute: true,
        nodir: true  // 不包括目录本身
      });

      cssFiles.forEach(file => {
        const relativePath = path.relative(cssDir, file);
        const content = readFileSync(file, 'utf-8');

        this$1.emitFile({
          type: 'asset',
          fileName: path.join('css', relativePath),
          source: content
        });
      });
    }
  }
});

/**
 * Rollup 插件列表
 *
 * 按照执行顺序排列：
 * 1. resolve - 解析模块路径
 * 2. babel - 转换 JSX
 * 3. commonjs - 转换 CommonJS 模块
 * 4. json - 解析 JSON 导入（但被标记为 external，不会实际转换）
 * 5. copyTypesPlugin - 复制类型、样式和图片文件
 * 6. terser - 代码压缩
 */
const plugins = [
  // 模块解析插件 - 解析 node_modules 中的模块
  resolve({
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
    browser: true  // 浏览器环境优先
  }),

  // Babel 转换插件 - 只转换 JSX
  babel(babelConfig),

  // CommonJS 转换插件 - 允许导入 CommonJS 模块
  commonjs({
    transformMixedEsModules: true  // 转换混合的 ES 模块
  }),

  // JSON 插件 - 处理 JSON 导入（配合 external 使用）
  json(),

  // 自定义插件 - 复制类型和样式文件
  copyTypesPlugin(),

  // 代码压缩插件
  terser({
    compress: {
      drop_console: false,       // 保留 console
      drop_debugger: true,       // 移除 debugger
      pure_funcs: [],            // 不移除任何函数调用
      passes: 2                  // 压缩次数
    },
    format: {
      comments: false,           // 移除注释
      beautify: false            // 不美化代码，保持压缩格式
    },
    ecma: 2015,                  // 目标 ECMAScript 版本
    module: true,                // 保留 ES 模块格式
    toplevel: false              // 不压缩顶层作用域
  })
];

/**
 * External 函数
 *
 * 判断模块是否应该标记为"外部依赖"
 * 外部依赖不会被打包进 bundle，而是保留 import 语句
 *
 * @param {string} id - 模块标识符
 * @returns {boolean} - true 表示外部依赖，不打包
 */
const external = (id) => {
  // 1. 样式文件标记为外部 -> 保留 import 语句
  //    原因：样式文件需要消费者项目配置自己的加载器来处理
  //    保持 Less 变量（如 @{ant-prefix}）不被替换
  if (id.endsWith('.less') || id.endsWith('.css') || id.endsWith('.scss') || id.endsWith('.sass')) {
    return true;
  }

  // 2. JSON 文件标记为外部 -> 直接使用原始 .json 文件
  //    原因：避免将 JSON 转换成 JS 模块，保持原始格式
  //    例如：35MB 的 area.json 不会被转换成 56MB 的 area.json.js
  if (id.endsWith('.json')) {
    return true;
  }

  // 3. 图片文件标记为外部 -> 保留 import 语句，直接使用原始文件
  //    原因：图片文件会通过 copyTypesPlugin 复制到输出目录
  if (id.endsWith('.png') || id.endsWith('.jpg') || id.endsWith('.jpeg') ||
      id.endsWith('.gif') || id.endsWith('.svg') || id.endsWith('.webp')) {
    return true;
  }

  // 4. npm 依赖包标记为外部 -> 不打包到 bundle 中
  //    原因：减少 bundle 体积，避免版本冲突，让消费者项目自己管理依赖
  //    从 package.json 的 dependencies 中读取依赖列表
  const dependencies = Object.keys(pkg.dependencies || {});
  return dependencies.some(dep => id === dep || id.startsWith(dep + '/'));
};

/**
 * 创建 Rollup 配置的辅助函数
 *
 * @param {string} outputDir - 输出目录
 * @param {string} format - 输出格式（'esm' 或 'cjs'）
 * @param {Array} plugins - 插件列表
 * @returns {Object} Rollup 配置对象
 */
function createConfig(outputDir, format, plugins) {
  return {
    // 入口文件对象
    input: getEntryFiles(),

    // 输出配置
    output: {
      dir: outputDir,                    // 输出目录
      format: format,                    // 输出格式：'esm' 或 'cjs'
      preserveModules: true,             // 保留模块结构，不打包成单个文件
      preserveModulesRoot: './',         // 保留模块结构的根目录
      entryFileNames: '[name]',          // 入口文件名：[name] 保留原始文件名（包括 .js 后缀）
      exports: 'named'                   // 导出命名导出
    },

    // 外部依赖判断函数
    external,

    // 插件列表
    plugins
  };
}

/**
 * 导出配置
 *
 * 只输出 ESM 格式到根目录（components/, hooks/, utils/ 等）
 */
export default createConfig('.', 'esm', plugins);
