import { getFs } from '../nodejs/fs.mjs';
import { getPath } from '../nodejs/path.mjs';

function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
var DEFAULT_EXTENSIONS = ['.vue', '.js', '.ts', '.less', '.css', '.scss'];
/**
 * 递归获取目录下所有匹配扩展名的文件
 * @example
 * ```ts
 * // 默认扫描 .vue/.js/.ts/.less/.css/.scss
 * const files = getAllFiles('/path/to/src');
 *
 * // 自定义扫描扩展名
 * const tsFiles = getAllFiles('/path/to/src', ['.ts', '.tsx']);
 * ```
 */
function getAllFiles(dirPath) {
  var extensions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_EXTENSIONS;
  var fileList = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
  var fs = getFs();
  if (!fs.existsSync(dirPath)) return fileList;
  var files = fs.readdirSync(dirPath);
  var _iterator = _createForOfIteratorHelper(files),
    _step;
  try {
    for (_iterator.s(); !(_step = _iterator.n()).done;) {
      var file = _step.value;
      var filePath = getPath().join(dirPath, file);
      var stat = fs.statSync(filePath);
      if (stat.isDirectory()) {
        getAllFiles(filePath, extensions, fileList);
      } else if (extensions.includes(getPath().extname(filePath))) {
        fileList.push(filePath);
      }
    }
  } catch (err) {
    _iterator.e(err);
  } finally {
    _iterator.f();
  }
  return fileList;
}
/**
 * 将 alias 路径转换为相对路径
 * @example
 * ```ts
 * toRelativePath(
 *   '/proj/src/views/Home/index.vue',
 *   'src',
 *   'components/Button/index.vue',
 *   '/proj',
 *   { src: 'src' },
 * );
 * // '../../components/Button/index.vue'
 * ```
 */
function toRelativePath(filePath, alias, subPath, rootDir, aliasMap) {
  var path = getPath();
  var targetDir = aliasMap[alias];
  var targetAbsPath = path.resolve(rootDir, targetDir, subPath);
  var fileDir = path.dirname(filePath);
  var relativePath = path.relative(fileDir, targetAbsPath);
  if (!relativePath.startsWith('.')) {
    relativePath = "./".concat(relativePath);
  }
  relativePath = relativePath.split(path.sep).join('/');
  return relativePath;
}
/**
 * 替换文件内容中单个 alias 的引入为相对路径
 */
function replaceContentForAlias(content, alias, filePath, rootDir, aliasMap) {
  var escapedAlias = alias.replace(/[.*+?^${}()|[\\]\\]/g, '\\$&');
  var regex = new RegExp("(['\"])".concat(escapedAlias, "/([^'\"]+)(['\"])"), 'g');
  var replaced = false;
  var newContent = content.replace(regex, function (match, quote1, sub, quote2) {
    var rel = toRelativePath(filePath, alias, sub, rootDir, aliasMap);
    replaced = true;
    return "".concat(quote1).concat(rel).concat(quote2);
  });
  return {
    content: newContent,
    replaced: replaced
  };
}
/**
 * 替换单个文件中的 alias 引入为相对路径
 * @example
 * ```ts
 * // 假设文件内原本写的是 `from 'src/components/Btn.vue'`
 * // 调用后会被改写为 `from '../../components/Btn.vue'`
 * const result = replaceAliasInFile(
 *   '/proj/src/views/Home/index.vue',
 *   '/proj',
 *   { src: 'src' },
 * );
 * // { replaced: true, error: null }
 * ```
 */
function replaceAliasInFile(filePath, rootDir, aliasMap) {
  try {
    var content = getFs().readFileSync(filePath, 'utf-8');
    var hasReplaced = false;
    for (var _i = 0, _Object$keys = Object.keys(aliasMap); _i < _Object$keys.length; _i++) {
      var alias = _Object$keys[_i];
      var result = replaceContentForAlias(content, alias, filePath, rootDir, aliasMap);
      content = result.content;
      if (result.replaced) {
        hasReplaced = true;
      }
    }
    if (hasReplaced) {
      getFs().writeFileSync(filePath, content, 'utf-8');
    }
    return {
      replaced: hasReplaced,
      error: null
    };
  } catch (err) {
    return {
      replaced: false,
      error: err.message
    };
  }
}
/**
 * 收集所有需要扫描的文件列表
 * @example
 * ```ts
 * const files = collectFiles({
 *   rootDir: '/proj',
 *   aliasMap: { src: 'src' },
 *   scanDirs: ['src/views', 'src/components'],
 *   scanRootFiles: ['vite.config.ts'],
 * });
 * ```
 */
function collectFiles(options) {
  var rootDir = options.rootDir,
    scanDirs = options.scanDirs,
    _options$scanRootFile = options.scanRootFiles,
    scanRootFiles = _options$scanRootFile === void 0 ? [] : _options$scanRootFile,
    _options$supportedExt = options.supportedExtensions,
    supportedExtensions = _options$supportedExt === void 0 ? DEFAULT_EXTENSIONS : _options$supportedExt;
  var allFiles = [];
  var _iterator2 = _createForOfIteratorHelper(scanDirs),
    _step2;
  try {
    for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
      var dir = _step2.value;
      var dirPath = getPath().resolve(rootDir, dir);
      getAllFiles(dirPath, supportedExtensions, allFiles);
    }
  } catch (err) {
    _iterator2.e(err);
  } finally {
    _iterator2.f();
  }
  var _iterator3 = _createForOfIteratorHelper(scanRootFiles),
    _step3;
  try {
    for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
      var file = _step3.value;
      var filePath = getPath().resolve(rootDir, file);
      if (getFs().existsSync(filePath)) {
        allFiles.push(filePath);
      }
    }
  } catch (err) {
    _iterator3.e(err);
  } finally {
    _iterator3.f();
  }
  return allFiles;
}
/**
 * 执行 alias 路径替换
 * @param options - 替换配置
 * @returns 替换统计信息
 * @example
 * ```ts
 * const { replacedCount, errorCount } = replaceAlias({
 *   rootDir: '/proj',
 *   aliasMap: {
 *     src: 'src',
 *     '@': 'src',
 *   },
 *   scanDirs: ['src'],
 *   scanRootFiles: ['vite.config.ts', 'tsconfig.json'],
 *   supportedExtensions: ['.ts', '.vue', '.scss'],
 * });
 * console.log(`替换了 ${replacedCount} 个文件，${errorCount} 个出错`);
 * ```
 */
function replaceAlias(options) {
  var rootDir = options.rootDir,
    aliasMap = options.aliasMap;
  var allFiles = collectFiles(options);
  console.log('🔄 开始替换 alias 路径为相对路径...\n');
  var replacedCount = 0;
  var errorCount = 0;
  var _iterator4 = _createForOfIteratorHelper(allFiles),
    _step4;
  try {
    for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
      var filePath = _step4.value;
      var _replaceAliasInFile = replaceAliasInFile(filePath, rootDir, aliasMap),
        replaced = _replaceAliasInFile.replaced,
        error = _replaceAliasInFile.error;
      var relativePath = getPath().relative(rootDir, filePath);
      if (error) {
        console.log("  \u26A0\uFE0F  ".concat(relativePath, " (").concat(error, ")"));
        errorCount += 1;
      } else if (replaced) {
        console.log("  \u2705 ".concat(relativePath));
        replacedCount += 1;
      }
    }
  } catch (err) {
    _iterator4.e(err);
  } finally {
    _iterator4.f();
  }
  if (replacedCount === 0 && errorCount === 0) {
    console.log('  ℹ️  没有找到需要替换的 alias 路径');
  } else {
    console.log("\n\u2728 \u5171\u66FF\u6362\u4E86 ".concat(replacedCount, " \u4E2A\u6587\u4EF6\u4E2D\u7684 alias \u8DEF\u5F84"));
    if (errorCount > 0) {
      console.log("\u26A0\uFE0F  ".concat(errorCount, " \u4E2A\u6587\u4EF6\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u6587\u4EF6\u6743\u9650"));
    }
  }
  return {
    replacedCount: replacedCount,
    errorCount: errorCount
  };
}

export { collectFiles, getAllFiles, replaceAlias, replaceAliasInFile, toRelativePath };
