import _typeof from '@babel/runtime/helpers/typeof';
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import _toArray from '@babel/runtime/helpers/toArray';
import { get } from './get.mjs';

function internalSet(entity, paths, value, removeIfUndefined) {
  if (!paths.length) {
    return value;
  }
  var _paths = _toArray(paths),
    path = _paths[0],
    restPath = _paths.slice(1);
  var clone;
  if (!entity && typeof path === 'number') {
    clone = [];
  } else if (Array.isArray(entity)) {
    clone = _toConsumableArray(entity);
  } else {
    clone = Object.assign({}, entity);
  }
  // Delete prop if `removeIfUndefined` and value is undefined
  if (removeIfUndefined && value === undefined && restPath.length === 1) {
    // @ts-ignore
    delete clone[path][restPath[0]];
  } else {
    // @ts-ignore
    clone[path] = internalSet(clone[path], restPath, value, removeIfUndefined);
  }
  return clone;
}
function set(entity, paths, value) {
  var removeIfUndefined = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
  // Do nothing if `removeIfUndefined` and parent object not exist
  if (paths.length && removeIfUndefined && value === undefined
  // @ts-ignore
  && !get(entity, paths.slice(0, -1).join('.'))) {
    return entity;
  }
  return internalSet(entity, paths, value, removeIfUndefined);
}
function isObject(obj) {
  return _typeof(obj) === 'object' && obj !== null && Object.getPrototypeOf(obj) === Object.prototype;
}
function createEmpty(source) {
  return Array.isArray(source) ? [] : {};
}
var keys = typeof Reflect === 'undefined' ? Object.keys : Reflect.ownKeys;
/**
 * Merge objects which will create
 * @example
 * ```ts
 * merge({ a: 1 }, { b: 2 }); // { a: 1, b: 2 }
 *
 * // 深合并
 * merge({ a: { x: 1 } }, { a: { y: 2 } });
 * // { a: { x: 1, y: 2 } }
 *
 * // 后者覆盖前者
 * merge({ a: 1, b: 2 }, { b: 3 });
 * // { a: 1, b: 3 }
 *
 * // 数组：直接覆盖（不会合并）
 * merge({ a: [1, 2, 3] }, { a: [4] });
 * // { a: [4] }
 *
 * // 多源合并
 * merge({ a: 1 }, { b: 2 }, { c: 3 });
 * // { a: 1, b: 2, c: 3 }
 * ```
 */
function merge() {
  for (var _len = arguments.length, sources = new Array(_len), _key = 0; _key < _len; _key++) {
    sources[_key] = arguments[_key];
  }
  var clone = createEmpty(sources[0]);
  sources.forEach(function (src) {
    function internalMerge(path, parentLoopSet) {
      var loopSet = new Set(parentLoopSet);
      var value = get(src, path.join('.'));
      var isArr = Array.isArray(value);
      if (isArr || isObject(value)) {
        // Only add not loop obj
        if (!loopSet.has(value)) {
          loopSet.add(value);
          var originValue = get(clone, path.join('.'));
          if (isArr) {
            // Array will always be override
            clone = set(clone, path, []);
          } else if (!originValue || _typeof(originValue) !== 'object') {
            // Init container if not exist
            clone = set(clone, path, createEmpty(value));
          }
          keys(value).forEach(function (key) {
            internalMerge([].concat(_toConsumableArray(path), [key]), loopSet);
          });
        }
      } else {
        clone = set(clone, path, value);
      }
    }
    internalMerge([]);
  });
  return clone;
}

export { merge, set };
