var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var lazy_exports = {};
__export(lazy_exports, {
  Iterator: () => Iterator,
  Lazy: () => Lazy,
  concat: () => concat
});
module.exports = __toCommonJS(lazy_exports);
var import_util = require("./util");
function Lazy(source) {
  return source instanceof Iterator ? source : new Iterator(source);
}
function concat(...iterators) {
  let index = 0;
  return Lazy(() => {
    while (index < iterators.length) {
      const o = iterators[index].next();
      if (!o.done) return o;
      index++;
    }
    return { done: true };
  });
}
function isGenerator(o) {
  return !!o && typeof o === "object" && typeof o?.next === "function";
}
function isIterable(o) {
  return !!o && (typeof o === "object" || typeof o === "function") && typeof o[Symbol.iterator] === "function";
}
class Iterator {
  #iteratees = [];
  #buffer = [];
  #getNext;
  #done = false;
  constructor(source) {
    const iter = isIterable(source) ? source[Symbol.iterator]() : isGenerator(source) ? source : typeof source === "function" ? { next: source } : null;
    (0, import_util.assert)(
      !!iter,
      `Iterator must be initialized with an iterable or function.`
    );
    let index = -1;
    let current = { done: false };
    this.#getNext = () => {
      while (!current.done) {
        current = iter.next();
        if (current.done) break;
        let value = current.value;
        index++;
        const ok = this.#iteratees.every(({ op: action, fn }) => {
          const res = fn(value, index);
          return action === "map" ? !!(value = res) || true : res;
        });
        if (ok) return { value, done: false };
      }
      return { done: true };
    };
  }
  /**
   * Add an iteratee to this lazy sequence
   */
  push(op, fn) {
    this.#iteratees.push({ op, fn });
    return this;
  }
  next() {
    return this.#getNext();
  }
  // Iteratees methods
  /**
   * Transform each item in the sequence to a new value
   * @param {Function} f
   */
  map(f) {
    return this.push("map", f);
  }
  /**
   * Select only items matching the given predicate
   * @param {Function} f
   */
  filter(f) {
    return this.push("filter", f);
  }
  /**
   * Take given numbe for values from sequence
   * @param {Number} n A number greater than 0
   */
  take(n) {
    return n > 0 ? this.filter((_) => !(n === 0 || n-- === 0)) : this;
  }
  /**
   * Drop a number of values from the sequence
   * @param {Number} n Number of items to drop greater than 0
   */
  drop(n) {
    return n > 0 ? this.filter((_) => n === 0 || n-- === 0) : this;
  }
  // Transformations
  /**
   * Returns a new lazy object with results of the transformation
   * The entire sequence is realized.
   *
   * @param {Callback<Source, Any[]>} fn Tranform function of type (Array) => (Any)
   */
  transform(fn) {
    const self = this;
    let iter;
    return Lazy(() => {
      if (!iter) iter = Lazy(fn(self.value()));
      return iter.next();
    });
  }
  // Terminal methods
  /**
   * Returns the fully realized values of the iterators.
   * The return value will be an array unless `lazy.first()` was used.
   * The realized values are cached for subsequent calls.
   */
  value() {
    while (!this.#done) {
      const { done, value } = this.#getNext();
      if (!done) this.#buffer.push(value);
      this.#done = done;
    }
    return this.#buffer;
  }
  /**
   * Execute the funcion for each value. Will stop when an execution returns false.
   * @param {Function} f
   * @returns {Boolean} false iff `f` return false for AnyVal execution, otherwise true
   */
  each(f) {
    for (; ; ) {
      const o = this.next();
      if (o.done) break;
      if (f(o.value) === false) return false;
    }
    return true;
  }
  /**
   * Returns the reduction of sequence according the reducing function
   *
   * @param {*} f a reducing function
   * @param {*} initialValue
   */
  reduce(f, initialValue) {
    let o = this.next();
    if (initialValue === void 0 && !o.done) {
      initialValue = o.value;
      o = this.next();
    }
    while (!o.done) {
      initialValue = f(initialValue, o.value);
      o = this.next();
    }
    return initialValue;
  }
  /**
   * Returns the number of matched items in the sequence
   */
  size() {
    return this.reduce(
      (acc, _) => ++acc,
      0
    );
  }
  [Symbol.iterator]() {
    return this;
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  Iterator,
  Lazy,
  concat
});
