import { isArray } from "@thi.ng/checks/is-array";
import { identity } from "@thi.ng/compose/identity";
import { illegalState } from "@thi.ng/errors/illegal-state";
import { __iter, iterator } from "./iterator.js";
import { isReduced } from "./reduced.js";
function partitionSync(...args) {
  const iter = __iter(partitionSync, args, iterator);
  if (iter) return iter;
  const {
    key = identity,
    mergeOnly = false,
    reset = true,
    all = true,
    backPressure = 0
  } = args[1];
  const requiredKeys = isArray(args[0]) ? new Set(args[0]) : args[0];
  const currKeys = /* @__PURE__ */ new Set();
  const cache = /* @__PURE__ */ new Map();
  let curr = {};
  const xform = ([init, complete, reduce]) => {
    let first = true;
    if (mergeOnly || backPressure < 1) {
      return [
        init,
        (acc) => {
          if (reset && all && currKeys.size > 0 || !reset && first) {
            acc = reduce(acc, curr);
            curr = {};
            currKeys.clear();
            first = false;
          }
          return complete(acc);
        },
        (acc, x) => {
          const k = key(x);
          if (requiredKeys.has(k)) {
            curr[k] = x;
            currKeys.add(k);
            if (mergeOnly || __requiredInputs(requiredKeys, currKeys)) {
              acc = reduce(acc, curr);
              first = false;
              if (reset) {
                curr = {};
                currKeys.clear();
              } else {
                curr = { ...curr };
              }
            }
          }
          return acc;
        }
      ];
    } else {
      return [
        init,
        (acc) => {
          if (all && currKeys.size > 0) {
            acc = reduce(acc, __collect(cache, currKeys));
            cache.clear();
            currKeys.clear();
          }
          return complete(acc);
        },
        (acc, x) => {
          const k = key(x);
          if (requiredKeys.has(k)) {
            let slot = cache.get(k);
            !slot && cache.set(k, slot = []);
            slot.length >= backPressure && illegalState(
              `max back pressure (${backPressure}) exceeded for input: ${String(
                k
              )}`
            );
            slot.push(x);
            currKeys.add(k);
            while (__requiredInputs(requiredKeys, currKeys)) {
              acc = reduce(acc, __collect(cache, currKeys));
              first = false;
              if (isReduced(acc)) break;
            }
          }
          return acc;
        }
      ];
    }
  };
  xform.keys = () => requiredKeys;
  xform.clear = () => {
    cache.clear();
    requiredKeys.clear();
    currKeys.clear();
    curr = {};
  };
  xform.add = (id) => {
    requiredKeys.add(id);
  };
  xform.delete = (id, clean = true) => {
    cache.delete(id);
    requiredKeys.delete(id);
    if (clean) {
      currKeys.delete(id);
      delete curr[id];
    }
  };
  return xform;
}
const __requiredInputs = (required, curr) => {
  if (curr.size < required.size) return false;
  for (let id of required) {
    if (!curr.has(id)) return false;
  }
  return true;
};
const __collect = (cache, currKeys) => {
  const curr = {};
  for (let id of currKeys) {
    const slot = cache.get(id);
    curr[id] = slot.shift();
    !slot.length && currKeys.delete(id);
  }
  return curr;
};
export {
  partitionSync
};
