import { traverseFolder } from '../fs/fs-util.mjs';
import { getChildProcess } from '../nodejs/child_process.mjs';
import { getFs } from '../nodejs/fs.mjs';
import { getOs } from '../nodejs/os.mjs';
import { getPath } from '../nodejs/path.mjs';
import '@babel/runtime/helpers/toConsumableArray';
import '../fs/fs.mjs';
import '../nodejs/crypto.mjs';
import '../time/time.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_EXCLUDE_GLOBS = ['*.map'];
function tryZipBin(options) {
  var fs = getFs();
  var path = getPath();
  var os = getOs();
  var _getChildProcess = getChildProcess(),
    execFileSync = _getChildProcess.execFileSync;
  var tmpZip = path.join(os.tmpdir(), "t-comm-zip-size-".concat(Date.now(), "-").concat(Math.random().toString(36).slice(2, 8), ".zip"));
  var excludeArgs = [];
  var _iterator = _createForOfIteratorHelper(options.excludeGlobs),
    _step;
  try {
    for (_iterator.s(); !(_step = _iterator.n()).done;) {
      var g = _step.value;
      excludeArgs.push('-x', g);
    }
  } catch (err) {
    _iterator.e(err);
  } finally {
    _iterator.f();
  }
  try {
    // -r 递归 -q 静默 -X 不带额外属性 -9 最大压缩比
    // cwd 设为产物目录，避免把绝对路径写入包
    execFileSync(options.zipBin, ['-rqX9', tmpZip, '.'].concat(excludeArgs), {
      cwd: options.outputDir,
      stdio: ['ignore', 'ignore', 'ignore']
    });
    var _fs$statSync = fs.statSync(tmpZip),
      size = _fs$statSync.size;
    try {
      fs.unlinkSync(tmpZip);
    } catch (_) {/* ignore */}
    return {
      zipSize: size,
      zipMethod: 'zip'
    };
  } catch (_) {
    try {
      fs.unlinkSync(tmpZip);
    } catch (__) {/* ignore */}
    return null;
  }
}
function listAllFiles(root, excludeMap) {
  var path = getPath();
  var result = [];
  traverseFolder(function (filePath) {
    if (excludeMap && /\.map$/i.test(filePath)) return;
    result.push(path.relative(root, filePath));
  }, root);
  return result;
}
function tryGzipSum(options) {
  var _a, _b;
  var fs = getFs();
  var path = getPath();
  try {
    // eslint-disable-next-line @typescript-eslint/no-require-imports
    var zlib = require('zlib');
    var list = (_b = (_a = options.files) === null || _a === void 0 ? void 0 : _a.map(function (f) {
      return f.name;
    })) !== null && _b !== void 0 ? _b : listAllFiles(options.outputDir, options.excludeMapInGzip);
    var sum = 0;
    var _iterator2 = _createForOfIteratorHelper(list),
      _step2;
    try {
      for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
        var name = _step2.value;
        if (options.excludeMapInGzip && /\.map$/i.test(name)) continue;
        var buf = fs.readFileSync(path.join(options.outputDir, name));
        // Buffer 在运行时完全兼容 InputType，但 Node 类型定义中 Buffer.buffer 可能为 SharedArrayBuffer，
        // 导致类型检查失败。使用 Uint8Array.from(buf) 显式转换可消除类型错误且零运行时开销。
        var input = Uint8Array.from(buf);
        sum += zlib.gzipSync(input, {
          level: 9
        }).length;
      }
    } catch (err) {
      _iterator2.e(err);
    } finally {
      _iterator2.f();
    }
    return {
      zipSize: sum,
      zipMethod: 'gzip-sum'
    };
  } catch (_) {
    return null;
  }
}
/**
 * 获取构建产物目录的 zip 压缩后体积，跨平台兜底。
 *
 * 估算策略：
 * 1) 优先调用系统 `zip` 命令打成真实 zip 包，删除后返回字节数（最准）
 * 2) 不可用时，降级为 `zlib.gzipSync` 逐文件累加（估算值，比真实 zip 略大，因为没有共享字典）
 * 3) 仍失败则返回 `{ zipSize: null, zipMethod: 'none' }`
 *
 * Windows 默认没有 `zip` 命令，会自动降级到 gzip-sum，无需额外配置。
 *
 * @example
 * ```ts
 * import { getZipSize } from 't-comm';
 *
 * const { zipSize, zipMethod } = getZipSize({ outputDir: '/path/to/dist' });
 * console.log(zipSize, zipMethod); // 1234567 'zip'
 * ```
 */
function getZipSize(options) {
  var outputDir = options.outputDir,
    files = options.files,
    _options$excludeGlobs = options.excludeGlobs,
    excludeGlobs = _options$excludeGlobs === void 0 ? DEFAULT_EXCLUDE_GLOBS : _options$excludeGlobs,
    _options$excludeMapIn = options.excludeMapInGzip,
    excludeMapInGzip = _options$excludeMapIn === void 0 ? true : _options$excludeMapIn,
    _options$zipBin = options.zipBin,
    zipBin = _options$zipBin === void 0 ? 'zip' : _options$zipBin;
  // 方式一：系统 zip 命令
  var fromZip = tryZipBin({
    outputDir: outputDir,
    excludeGlobs: excludeGlobs,
    zipBin: zipBin
  });
  if (fromZip) return fromZip;
  // 方式二：逐文件 gzip 累加
  var fromGzip = tryGzipSum({
    outputDir: outputDir,
    excludeMapInGzip: excludeMapInGzip,
    files: files
  });
  if (fromGzip) return fromGzip;
  return {
    zipSize: null,
    zipMethod: 'none'
  };
}

export { getZipSize };
