function get(obj, path) {
  if (obj == null)
    return void 0;
  let value = obj;
  for (let i = 0; i < path.length; i++) {
    if (value == null || value[path[i]] == null)
      return void 0;
    value = value[path[i]];
  }
  return value;
}
function set(obj, value, path) {
  if (path.length === 0)
    return value;
  const idx = path[0];
  if (path.length > 1) {
    value = set(
      typeof obj !== "object" || obj === null || !Object.prototype.hasOwnProperty.call(obj, idx) ? Number.isInteger(Number(path[1])) ? [] : {} : obj[idx],
      value,
      Array.prototype.slice.call(path, 1)
    );
  }
  if (Number.isInteger(Number(idx)) && Array.isArray(obj))
    return obj.slice()[idx];
  return Object.assign({}, obj, { [idx]: value });
}
function unset(obj, path) {
  if (obj == null || path.length === 0)
    return obj;
  if (path.length === 1) {
    if (obj == null)
      return obj;
    if (Number.isInteger(path[0]) && Array.isArray(obj))
      return Array.prototype.slice.call(obj, 0).splice(path[0], 1);
    const result = {};
    for (const p in obj)
      result[p] = obj[p];
    delete result[path[0]];
    return result;
  }
  if (obj[path[0]] == null) {
    if (Number.isInteger(path[0]) && Array.isArray(obj))
      return Array.prototype.concat.call([], obj);
    const result = {};
    for (const p in obj)
      result[p] = obj[p];
    return result;
  }
  return set(
    obj,
    unset(
      obj[path[0]],
      Array.prototype.slice.call(path, 1)
    ),
    [path[0]]
  );
}

function deepPickUnsafe(obj, paths) {
  return paths.map((p) => p.split(".")).map((p) => [p, get(obj, p)]).filter((t) => t[1] !== void 0).reduce((acc, cur) => set(acc, cur[1], cur[0]), {});
}
function deepPick(obj, paths) {
  return deepPickUnsafe(obj, paths);
}
function deepOmitUnsafe(obj, paths) {
  return paths.map((p) => p.split(".")).reduce((acc, cur) => unset(acc, cur), obj);
}
function deepOmit(obj, paths) {
  return deepOmitUnsafe(obj, paths);
}

export { deepOmit, deepOmitUnsafe, deepPick, deepPickUnsafe };
