import equal from "../../../../@gilbarbara_deep-equal@0.3.1/node_modules/@gilbarbara/deep-equal/dist/index.js";
import src_default from "../../../../is-lite@1.2.1/node_modules/is-lite/dist/index.js";
function canHaveLength(...arguments_) {
  return arguments_.every((d) => src_default.string(d) || src_default.array(d) || src_default.plainObject(d));
}
function checkEquality(left, right, value) {
  if (!isSameType(left, right)) {
    return false;
  }
  if ([left, right].every(src_default.array)) {
    return !left.some(hasValue(value)) && right.some(hasValue(value));
  }
  if ([left, right].every(src_default.plainObject)) {
    return !Object.entries(left).some(hasEntry(value)) && Object.entries(right).some(hasEntry(value));
  }
  return right === value;
}
function compareNumbers(previousData, data, options) {
  const { actual, key, previous, type } = options;
  const left = nested(previousData, key);
  const right = nested(data, key);
  let changed = [left, right].every(src_default.number) && (type === "increased" ? left < right : left > right);
  if (!src_default.undefined(actual)) {
    changed = changed && right === actual;
  }
  if (!src_default.undefined(previous)) {
    changed = changed && left === previous;
  }
  return changed;
}
function compareValues(previousData, data, options) {
  const { key, type, value } = options;
  const left = nested(previousData, key);
  const right = nested(data, key);
  const primary = type === "added" ? left : right;
  const secondary = type === "added" ? right : left;
  if (!src_default.nullOrUndefined(value)) {
    if (src_default.defined(primary)) {
      if (src_default.array(primary) || src_default.plainObject(primary)) {
        return checkEquality(primary, secondary, value);
      }
    } else {
      return equal(secondary, value);
    }
    return false;
  }
  if ([left, right].every(src_default.array)) {
    return !secondary.every(isEqualPredicate(primary));
  }
  if ([left, right].every(src_default.plainObject)) {
    return hasExtraKeys(Object.keys(primary), Object.keys(secondary));
  }
  return ![left, right].every((d) => src_default.primitive(d) && src_default.defined(d)) && (type === "added" ? !src_default.defined(left) && src_default.defined(right) : src_default.defined(left) && !src_default.defined(right));
}
function getIterables(previousData, data, { key } = {}) {
  let left = nested(previousData, key);
  let right = nested(data, key);
  if (!isSameType(left, right)) {
    throw new TypeError("Inputs have different types");
  }
  if (!canHaveLength(left, right)) {
    throw new TypeError("Inputs don't have length");
  }
  if ([left, right].every(src_default.plainObject)) {
    left = Object.keys(left);
    right = Object.keys(right);
  }
  return [left, right];
}
function hasEntry(input) {
  return ([key, value]) => {
    if (src_default.array(input)) {
      return equal(input, value) || input.some((d) => equal(d, value) || src_default.array(value) && isEqualPredicate(value)(d));
    }
    if (src_default.plainObject(input) && input[key]) {
      return !!input[key] && equal(input[key], value);
    }
    return equal(input, value);
  };
}
function hasExtraKeys(left, right) {
  return right.some((d) => !left.includes(d));
}
function hasValue(input) {
  return (value) => {
    if (src_default.array(input)) {
      return input.some((d) => equal(d, value) || src_default.array(value) && isEqualPredicate(value)(d));
    }
    return equal(input, value);
  };
}
function includesOrEqualsTo(previousValue, value) {
  return src_default.array(previousValue) ? previousValue.some((d) => equal(d, value)) : equal(previousValue, value);
}
function isEqualPredicate(data) {
  return (value) => data.some((d) => equal(d, value));
}
function isSameType(...arguments_) {
  return arguments_.every(src_default.array) || arguments_.every(src_default.number) || arguments_.every(src_default.plainObject) || arguments_.every(src_default.string);
}
function nested(data, property) {
  if (src_default.plainObject(data) || src_default.array(data)) {
    if (src_default.string(property)) {
      const props = property.split(".");
      return props.reduce((acc, d) => acc && acc[d], data);
    }
    if (src_default.number(property)) {
      return data[property];
    }
    return data;
  }
  return data;
}
function treeChanges(previousData, data) {
  if ([previousData, data].some(src_default.nullOrUndefined)) {
    throw new Error("Missing required parameters");
  }
  if (![previousData, data].every((d) => src_default.plainObject(d) || src_default.array(d))) {
    throw new Error("Expected plain objects or array");
  }
  const added = (key, value) => {
    try {
      return compareValues(previousData, data, { key, type: "added", value });
    } catch {
      return false;
    }
  };
  const changed = (key, actual, previous) => {
    try {
      const left = nested(previousData, key);
      const right = nested(data, key);
      const hasActual = src_default.defined(actual);
      const hasPrevious = src_default.defined(previous);
      if (hasActual || hasPrevious) {
        const leftComparator = hasPrevious ? includesOrEqualsTo(previous, left) : !includesOrEqualsTo(actual, left);
        const rightComparator = includesOrEqualsTo(actual, right);
        return leftComparator && rightComparator;
      }
      if ([left, right].every(src_default.array) || [left, right].every(src_default.plainObject)) {
        return !equal(left, right);
      }
      return left !== right;
    } catch {
      return false;
    }
  };
  const changedFrom = (key, previous, actual) => {
    if (!src_default.defined(key)) {
      return false;
    }
    try {
      const left = nested(previousData, key);
      const right = nested(data, key);
      const hasActual = src_default.defined(actual);
      return includesOrEqualsTo(previous, left) && (hasActual ? includesOrEqualsTo(actual, right) : !hasActual);
    } catch {
      return false;
    }
  };
  const decreased = (key, actual, previous) => {
    if (!src_default.defined(key)) {
      return false;
    }
    try {
      return compareNumbers(previousData, data, { key, actual, previous, type: "decreased" });
    } catch {
      return false;
    }
  };
  const emptied = (key) => {
    try {
      const [left, right] = getIterables(previousData, data, { key });
      return !!left.length && !right.length;
    } catch {
      return false;
    }
  };
  const filled = (key) => {
    try {
      const [left, right] = getIterables(previousData, data, { key });
      return !left.length && !!right.length;
    } catch {
      return false;
    }
  };
  const increased = (key, actual, previous) => {
    if (!src_default.defined(key)) {
      return false;
    }
    try {
      return compareNumbers(previousData, data, { key, actual, previous, type: "increased" });
    } catch {
      return false;
    }
  };
  const removed = (key, value) => {
    try {
      return compareValues(previousData, data, { key, type: "removed", value });
    } catch {
      return false;
    }
  };
  return { added, changed, changedFrom, decreased, emptied, filled, increased, removed };
}
export {
  treeChanges as default
};
//# sourceMappingURL=index.js.map
