"use strict";var _WeakMap = require("@babel/runtime-corejs2/core-js/weak-map");var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/define-property");var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs2/core-js/object/get-own-property-descriptor");var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");_Object$defineProperty(exports, "__esModule", { value: true });exports.default = rpk;var _stringify = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/json/stringify"));var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));var _path = _interopRequireDefault(require("path"));
var _jszip = _interopRequireDefault(require("jszip"));
var _crypto = _interopRequireDefault(require("crypto"));
var _index = require("../../cli-shared-utils/index.js");
var _bundle = require("./bundle.js");
var _constanst = require("./constanst.js");
var fflate = _interopRequireWildcard(require("fflate"));function _getRequireWildcardCache(e) {if ("function" != typeof _WeakMap) return null;var r = new _WeakMap(),t = new _WeakMap();return (_getRequireWildcardCache = function (e) {return e ? t : r;})(e);}function _interopRequireWildcard(e, r) {if (!r && e && e.__esModule) return e;if (null === e || "object" != typeof e && "function" != typeof e) return { default: e };var t = _getRequireWildcardCache(r);if (t && t.has(e)) return t.get(e);var n = { __proto__: null },a = _Object$defineProperty && _Object$getOwnPropertyDescriptor;for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {var i = a ? _Object$getOwnPropertyDescriptor(e, u) : null;i && (i.get || i.set) ? _Object$defineProperty(n, u, i) : n[u] = e[u];}return n.default = e, t && t.set(e, n), n;}

// 文件摘要包（zip 文件）
const DIGEST_ZIP_PATH = 'META-INF/CERT';
// 压缩参数，设置输出 buffer，以便对 buffer 进行操作
const COMPRESS_OPTS = {
  type: 'nodebuffer',
  compression: 'DEFLATE',
  compressionOptions: {
    level: 9
  }
};

// 获取buf的hash
function getBufferDigest(buf) {
  const signer = _crypto.default.createHash('SHA256');
  signer.update(buf);
  return signer.digest();
}
/**
 * 返回摘要文件签名buff d
 * @param {} fileHashObj - 文件资源列表和对应hash
 * @param {Buffer} privatekey - 私钥文件 buffer
 * @param {Buffer} certificate - 证书文件 buffer
 * @returns {Object} signedDigestBuf - 摘要文件签名buff
 */
async function signZipResourcesMeta(fileHashObj, privatekey, certificate, pathTo) {
  // ZIP元文件
  const metaZipFile = new _jszip.default();
  metaZipFile.file(
    'hash.json',
    (0, _stringify.default)({
      algorithm: 'SHA-256',
      digests: fileHashObj
    })
  );
  const content = await metaZipFile.generateAsync(COMPRESS_OPTS);
  const digestHash = {
    name: 'hash.json',
    hash: getBufferDigest(content)
  };
  return (0, _bundle.signZip)(content, [digestHash], privatekey, certificate);
}
/**
 * 对文件进行重新 排序
 * 第一位 入口文件 第二位 js文件 第三位 manifest（读取到这个文件引擎会执行js）
 * 第四位 icon和防沉迷页面图片 第五位 游戏的资源文件
 * @param {Array(String)} res 文件路径数组
 * @param {Object} manifest 小游戏配置文件
 */
function sortAgain(res, manifest) {
  const firstFileArr = ['main.js', 'game.js'];
  const firstFile = [];
  const secondFile = [];
  const imageFileArr = [manifest && manifest.icon.substr(1), manifest && manifest.homePage && manifest.homePage.substr(1)];
  const imageFile = [];
  const manifestFileArr = ['manifest.json'];
  const manifestFile = [];
  const lastFile = [];
  if (!res) {return [];}
  // 将输入数组深拷贝，避免源数据被修改，执行后续操作时出问题
  const newRes = JSON.parse((0, _stringify.default)(res));
  for (let index = newRes.length - 1; index >= 0; index--) {
    const element = newRes[index];
    const extname = _path.default.extname(element);
    if (firstFileArr.indexOf(element) > -1) {
      // 入口文件
      firstFile.push(element);
      newRes.splice(index, 1);
      // 其次是icon和首页图片
    } else if (extname === '.js') {
      // js文件
      secondFile.push(element);
      newRes.splice(index, 1);
    } else if (manifestFileArr.indexOf(element) > -1) {
      // 配置文件 manifest.json
      manifestFile.push(element);
      newRes.splice(index, 1);
    } else if (imageFileArr.indexOf(element) > -1) {
      // icon和防沉迷页面图片
      imageFile.push(element);
      newRes.splice(index, 1);
    } else {
      lastFile.push(element);
    }
  }
  return firstFile.concat(secondFile, manifestFile, imageFile, lastFile);
}
/**
 * 打rpk包
 * @param {String} name rpk包的文件名
 * @param {Array(String)} buildReses rpk对应的资源路径
 * @param {String} pathFrom 打包rpk到何处
 * @param {String} pathTo 打包rpk到何处
 * @param {Object} signFile 签名文件信息
 * @param {Object} manifest 小游戏配置文件
 */
async function rpk(name, buildReses, pathFrom, pathTo, signFile, manifest) {
  await fflateRpk(name, buildReses, pathFrom, pathTo, signFile, manifest);
}

async function fflateRpk(name, buildReses, pathFrom, pathTo, signFile, manifest) {
  // 保证打包路径存在，不存在就创建
  const rpkStartTime = new Date().valueOf();
  _index.fs.ensureDirSync(pathTo);
  (0, _index.info)(`${_constanst.LOG_TITLE}开始fflate压缩:${name} from:${pathFrom}`);

  const fileHashObj = {}; // 文件hash列表 缓存
  const zipFileHashs = []; // 文件hash列表打包使用
  const fileContents = {}; // fflate压缩的文件列表
  const privatekey = _index.fs.readFileSync(signFile.privatekey);
  const certificate = _index.fs.readFileSync(signFile.certificate);
  // 对打包的文件 进行排序
  const newBuildRess = sortAgain(buildReses, manifest);

  newBuildRess.forEach((name) => {
    const file = _path.default.join(pathFrom, name);
    const buf = _index.fs.readFileSync(file);
    const fileHash = getBufferDigest(buf);
    fileHashObj[name] = fileHash.toString('hex');
    zipFileHashs.push({
      name,
      hash: fileHash
    });

    // 添加文件到压缩文件列表
    fileContents[name] = new Uint8Array(buf);
  });

  const fflateZip = async (
  files,
  compressOptions) =>
  {
    try {
      const options = compressOptions || {};
      const zippedContent = await new _promise.default((resolve, reject) => {
        fflate.zip(files, options, (err, data) => {
          if (err) {
            reject(err);
          }
          resolve(data);
        });
      });
      return Buffer.from(zippedContent);
    } catch (err) {
      return _promise.default.reject(new Error(`compress failed: ${err}`));
    }
  };

  // fflate 打包zip包
  const content = await fflateZip(fileContents, { level: 9 });
  const size = Number(content.length / 1024).toFixed(2);

  // 对压缩包进行签名
  (0, _bundle.signZip)(content, zipFileHashs, privatekey, certificate, _path.default.join(pathTo, `${name}`));

  (0, _index.info)(`${_constanst.LOG_TITLE}压缩fflate完成:${name} 耗时：${(new Date().valueOf() - rpkStartTime) / 1000}s 大小：${size}Kb`);
}