import _sliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/slice";
import _Array$from from "@babel/runtime-corejs3/core-js-stable/array/from";
import _Symbol from "@babel/runtime-corejs3/core-js-stable/symbol";
import _getIteratorMethod from "@babel/runtime-corejs3/core-js/get-iterator-method";
import _slicedToArray from "@babel/runtime-corejs3/helpers/slicedToArray";

function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof _Symbol !== "undefined" && _getIteratorMethod(o) || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, 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 normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }

function _unsupportedIterableToArray(o, minLen) { var _context5; if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = _sliceInstanceProperty(_context5 = Object.prototype.toString.call(o)).call(_context5, 8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return _Array$from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

import _Set from "@babel/runtime-corejs3/core-js-stable/set";
import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";
import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter";
import _Map from "@babel/runtime-corejs3/core-js-stable/map";
import { groupBy, isLeafNode } from '../../utils';
import { always, fromEntries } from '../../utils/others';
import buildDrillTree from './buildDrillTree';
import simpleEncode from './simpleEncode';

function fallbackAggregate(slice) {
  return slice.length === 1 ? slice[0] : {};
}
/** 根据表格左侧与上方的下钻树，从全量明细数据中计算对应的数据立方 */


export function buildRecordMatrix(_ref) {
  var data = _ref.data,
      leftCodes = _ref.leftCodes,
      topCodes = _ref.topCodes,
      _ref$aggregate = _ref.aggregate,
      aggregate = _ref$aggregate === void 0 ? fallbackAggregate : _ref$aggregate,
      _ref$encode = _ref.encode,
      encode = _ref$encode === void 0 ? simpleEncode : _ref$encode,
      _ref$isLeftExpand = _ref.isLeftExpand,
      isLeftExpand = _ref$isLeftExpand === void 0 ? always(true) : _ref$isLeftExpand,
      _ref$isTopExpand = _ref.isTopExpand,
      isTopExpand = _ref$isTopExpand === void 0 ? always(true) : _ref$isTopExpand,
      prebuiltLeftTree = _ref.prebuiltLeftTree,
      prebuiltTopTree = _ref.prebuiltTopTree;
  var ctx = {
    peculiarity: new _Set()
  };

  var _ref2 = prebuiltLeftTree !== null && prebuiltLeftTree !== void 0 ? prebuiltLeftTree : buildDrillTree(data, leftCodes, {
    encode: encode,
    includeTopWrapper: true,
    isExpand: isLeftExpand
  }),
      _ref3 = _slicedToArray(_ref2, 1),
      leftRootDrillNode = _ref3[0];

  var _ref4 = prebuiltTopTree !== null && prebuiltTopTree !== void 0 ? prebuiltTopTree : buildDrillTree(data, topCodes, {
    encode: encode,
    includeTopWrapper: true,
    isExpand: isTopExpand
  }),
      _ref5 = _slicedToArray(_ref4, 1),
      topRootDrillNode = _ref5[0];

  var transientMatrixRow = buildByLeft(ctx, data, leftRootDrillNode, 0);
  return makeMatrix(transientMatrixRow);

  function buildByLeft(ctx, slice, drillNode, depth) {
    var children = null;
    var col;

    if (isLeafNode(drillNode)) {
      col = buildByTop(ctx, slice, topRootDrillNode, 0);
    } else {
      children = [];
      var code = leftCodes[depth];
      var groups = groupBy(slice, function (dwdRow) {
        return dwdRow[code];
      });
      ctx.peculiarity.add(code);

      var _iterator = _createForOfIteratorHelper(drillNode.children),
          _step;

      try {
        for (_iterator.s(); !(_step = _iterator.n()).done;) {
          var child = _step.value;
          var group = groups[child.value];

          if (group) {
            children.push(buildByLeft(ctx, group, child, depth + 1));
          }
        }
      } catch (err) {
        _iterator.e(err);
      } finally {
        _iterator.f();
      }

      ctx.peculiarity.delete(code);
      col = mergeColsByTopTree(ctx, _mapInstanceProperty(children).call(children, function (child) {
        return child.col;
      }));
    }

    return {
      leftKey: drillNode.key,
      children: children,
      col: col
    };
  }

  function buildByTop(ctx, slice, drillNode, depth) {
    var children = null;
    var record;

    if (isLeafNode(drillNode)) {
      record = aggregate(slice, ctx);
    } else {
      children = [];
      var code = topCodes[depth];
      var groups = groupBy(slice, function (dwdRow) {
        return dwdRow[code];
      });
      ctx.peculiarity.add(code);

      var _iterator2 = _createForOfIteratorHelper(drillNode.children),
          _step2;

      try {
        for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
          var child = _step2.value;
          var group = groups[child.value];

          if (group) {
            children.push(buildByTop(ctx, group, child, depth + 1));
          }
        }
      } catch (err) {
        _iterator2.e(err);
      } finally {
        _iterator2.f();
      }

      ctx.peculiarity.delete(code);
      record = aggregate(_mapInstanceProperty(children).call(children, function (child) {
        return child.record;
      }), ctx);
    }

    return {
      topKey: drillNode.key,
      topValue: drillNode.value,
      children: children,
      record: record
    };
  }

  function mergeColsByTopTree(ctx, colsToMerge) {
    return dfs(ctx, colsToMerge, topRootDrillNode, 0);

    function dfs(ctx, cols, topDrillNode, depth) {
      var children = null;
      var record = aggregate(_mapInstanceProperty(cols).call(cols, function (c) {
        return c.record;
      }), ctx);

      if (!isLeafNode(topDrillNode)) {
        var _context, _context3;

        var topCode = topCodes[depth];
        ctx.peculiarity.add(topCode);
        var drillChildDict = fromEntries(_mapInstanceProperty(_context = topDrillNode.children).call(_context, function (child) {
          return [child.value, child];
        }));

        var colChildDictArray = _mapInstanceProperty(cols).call(cols, function (col) {
          var _context2;

          return fromEntries(_mapInstanceProperty(_context2 = col.children).call(_context2, function (child) {
            return [child.topValue, child];
          }));
        });

        children = _mapInstanceProperty(_context3 = topDrillNode.children).call(_context3, function (item) {
          var _context4;

          var childCols = _filterInstanceProperty(_context4 = _mapInstanceProperty(colChildDictArray).call(colChildDictArray, function (colChildDict) {
            return colChildDict[item.value];
          })).call(_context4, Boolean);

          return dfs(ctx, childCols, drillChildDict[item.value], depth + 1);
        });
        ctx.peculiarity.delete(topCode);
      }

      return {
        topKey: topDrillNode.key,
        topValue: topDrillNode.value,
        record: record,
        children: children
      };
    }
  }

  function makeMatrix(rootRow) {
    var result = new _Map();
    dfsRow(result, rootRow);
    return result;

    function dfsRow(matrix, row) {
      var subMap = new _Map();
      matrix.set(row.leftKey, subMap);
      dfsCol(subMap, row.col);

      if (!isLeafNode(row)) {
        row.children.forEach(function (childRow) {
          dfsRow(matrix, childRow);
        });
      }
    }

    function dfsCol(subMap, col) {
      subMap.set(col.topKey, col.record);

      if (!isLeafNode(col)) {
        col.children.forEach(function (childCol) {
          dfsCol(subMap, childCol);
        });
      }
    }
  }
}
/** buildRecordMatrix 的简化版本，只能处理一个维度序列，返回一个 Map。
 * 相当于只处理 matrix 的第一行（汇总行） */

export function buildRecordMap(_ref6) {
  var codes = _ref6.codes,
      _ref6$encode = _ref6.encode,
      encode = _ref6$encode === void 0 ? simpleEncode : _ref6$encode,
      data = _ref6.data,
      aggregate = _ref6.aggregate,
      isExpand = _ref6.isExpand;
  var matrix = buildRecordMatrix({
    data: data,
    leftCodes: [],
    topCodes: codes,
    isTopExpand: isExpand,
    aggregate: aggregate,
    encode: encode
  });
  var totalKey = encode([]);
  return matrix.get(totalKey);
}