const fileName_1 = "(@effect/core) _src/stream/SortedByKey/operations/zipAllSortedByKeyWith.ts";
import * as tsplus_module_1 from "@effect/core/io/Exit/operations/fail";
import * as tsplus_module_2 from "@tsplus/stdlib/data/Tuple/make";
import * as tsplus_module_3 from "@tsplus/stdlib/collections/Chunk/map";
import * as tsplus_module_4 from "@effect/core/io/Exit/operations/succeed";
import * as tsplus_module_5 from "@effect/core/io/Effect/operations/fold";
import * as tsplus_module_6 from "@tsplus/stdlib/data/Maybe/definition";
import * as tsplus_module_7 from "@effect/core/io/Effect/operations/succeedNow";
import * as tsplus_module_8 from "@tsplus/stdlib/collections/Chunk/isEmpty";
import * as tsplus_module_9 from "@effect/core/io/Effect/operations/unsome";
import * as tsplus_module_10 from "@effect/core/io/Effect/operations/zipPar";
import * as tsplus_module_11 from "@effect/core/io/Effect/operations/foldEffect";
import * as tsplus_module_12 from "@tsplus/stdlib/data/Maybe/fold";
import * as tsplus_module_13 from "@tsplus/stdlib/collections/Chunk/builder";
import * as tsplus_module_14 from "@tsplus/stdlib/collections/Chunk/unsafeGet";
import * as tsplus_module_15 from "@tsplus/stdlib/collections/Chunk/size";
import * as tsplus_module_16 from "@tsplus/stdlib/collections/Chunk/drop";
import * as tsplus_module_17 from "@effect/core/stream/Stream/operations/combineChunks";
export class DrainLeft {
  constructor() {
    this._tag = "DrainLeft";
  }

}
export class DrainRight {
  constructor() {
    this._tag = "DrainRight";
  }

}
export class PullBoth {
  constructor() {
    this._tag = "PullBoth";
  }

}
export class PullLeft {
  constructor(rightChunk) {
    this.rightChunk = rightChunk;
    this._tag = "PullLeft";
  }

}
export class PullRight {
  constructor(leftChunk) {
    this.leftChunk = leftChunk;
    this._tag = "PullRight";
  }

}
/**
 * Zips this stream that is sorted by distinct keys and the specified stream
 * that is sorted by distinct keys to produce a new stream that is sorted by
 * distinct keys. Uses the functions `left`, `right`, and `both` to handle
 * the cases where a key and value exist in this stream, that stream, or
 * both streams.
 *
 * This allows zipping potentially unbounded streams of data by key in
 * constant space but the caller is responsible for ensuring that the
 * streams are sorted by distinct keys.
 *
 * @tsplus fluent ets/SortedByKey zipAllSortedByKeyWith
 * @tsplus fluent ets/Stream zipAllSortedByKeyWith
 */

export function zipAllSortedByKeyWith_(self, ord) {
  return (that, left, right, both, __tsplusTrace) => {
    const pull = (state, pullLeft, pullRight) => {
      switch (state._tag) {
        case "DrainLeft":
          return tsplus_module_5.fold_(pullLeft, e => tsplus_module_1.fail(e), leftChunk => tsplus_module_4.succeed(tsplus_module_2.make(tsplus_module_3.map_(leftChunk, ({
            tuple: [k, a]
          }) => tsplus_module_2.make(k, left(a))), new DrainLeft())), fileName_1 + ":66:31");

        case "DrainRight":
          return tsplus_module_5.fold_(pullRight, e => tsplus_module_1.fail(e), rightChunk => tsplus_module_4.succeed(tsplus_module_2.make(tsplus_module_3.map_(rightChunk, ({
            tuple: [k, b]
          }) => tsplus_module_2.make(k, right(b))), new DrainRight())), fileName_1 + ":77:32");

        case "PullBoth":
          {
            return tsplus_module_11.foldEffect_(tsplus_module_10.zipPar_(tsplus_module_9.unsome(pullLeft, fileName_1 + ":89:20"), () => tsplus_module_9.unsome(pullRight, fileName_1 + ":90:37"), fileName_1 + ":90:20"), e => tsplus_module_7.succeedNow(tsplus_module_1.fail(tsplus_module_6.some(e)), fileName_1 + ":92:39"), ({
              tuple: [a, b]
            }) => {
              if (tsplus_module_6.isSome(a) && tsplus_module_6.isSome(b)) {
                const leftChunk = a.value;
                const rightChunk = b.value;

                if (tsplus_module_8.isEmpty(leftChunk) && tsplus_module_8.isEmpty(rightChunk)) {
                  return pull(new PullBoth(), pullLeft, pullRight);
                } else if (tsplus_module_8.isEmpty(leftChunk)) {
                  return pull(new PullLeft(rightChunk), pullLeft, pullRight);
                } else if (tsplus_module_8.isEmpty(rightChunk)) {
                  return pull(new PullRight(leftChunk), pullLeft, pullRight);
                } else {
                  return tsplus_module_7.succeedNow(tsplus_module_4.succeed(mergeSortedByKeyChunk(leftChunk, rightChunk)), fileName_1 + ":105:45");
                }
              } else if (tsplus_module_6.isSome(a)) {
                const leftChunk = a.value;
                return tsplus_module_8.isEmpty(leftChunk) ? pull(new DrainLeft(), pullLeft, pullRight) : tsplus_module_7.succeedNow(tsplus_module_4.succeed(tsplus_module_2.make(tsplus_module_3.map_(leftChunk, ({
                  tuple: [k, a]
                }) => tsplus_module_2.make(k, left(a))), new DrainLeft())), fileName_1 + ":114:40");
              } else if (tsplus_module_6.isSome(b)) {
                const rightChunk = b.value;
                return tsplus_module_8.isEmpty(rightChunk) ? pull(new DrainLeft(), pullLeft, pullRight) : tsplus_module_7.succeedNow(tsplus_module_4.succeed(tsplus_module_2.make(tsplus_module_3.map_(rightChunk, ({
                  tuple: [k, b]
                }) => tsplus_module_2.make(k, right(b))), new DrainRight())), fileName_1 + ":127:40");
              } else {
                return tsplus_module_7.succeedNow(tsplus_module_1.fail(tsplus_module_6.none), fileName_1 + ":136:43");
              }
            }, fileName_1 + ":91:24");
          }

        case "PullLeft":
          {
            const rightChunk = state.rightChunk;
            return tsplus_module_11.foldEffect_(pullLeft, option => tsplus_module_12.fold_(option, () => tsplus_module_7.succeedNow(tsplus_module_4.succeed(tsplus_module_2.make(tsplus_module_3.map_(rightChunk, ({
              tuple: [k, b]
            }) => tsplus_module_2.make(k, right(b))), new DrainRight())), fileName_1 + ":152:36"), e => tsplus_module_7.succeedNow(tsplus_module_1.fail(tsplus_module_6.some(e)), fileName_1 + ":160:41")), leftChunk => tsplus_module_8.isEmpty(leftChunk) ? pull(new PullLeft(rightChunk), pullLeft, pullRight) : tsplus_module_7.succeedNow(tsplus_module_4.succeed(mergeSortedByKeyChunk(leftChunk, rightChunk)), fileName_1 + ":165:36"), fileName_1 + ":144:37");
          }

        case "PullRight":
          {
            const leftChunk = state.leftChunk;
            return tsplus_module_11.foldEffect_(pullRight, option => tsplus_module_12.fold_(option, () => tsplus_module_7.succeedNow(tsplus_module_4.succeed(tsplus_module_2.make(tsplus_module_3.map_(leftChunk, ({
              tuple: [k, a]
            }) => tsplus_module_2.make(k, left(a))), new DrainLeft())), fileName_1 + ":181:36"), e => tsplus_module_7.succeedNow(tsplus_module_1.fail(tsplus_module_6.some(e)), fileName_1 + ":189:41")), rightChunk => tsplus_module_8.isEmpty(rightChunk) ? pull(new PullRight(leftChunk), pullLeft, pullRight) : tsplus_module_7.succeedNow(tsplus_module_4.succeed(mergeSortedByKeyChunk(leftChunk, rightChunk)), fileName_1 + ":194:36"), fileName_1 + ":173:38");
          }
      }
    };

    function mergeSortedByKeyChunk(leftChunk, rightChunk) {
      const builder = tsplus_module_13.builder();
      let state;
      let leftIndex = 0;
      let rightIndex = 0;
      let leftTuple = tsplus_module_14.unsafeGet_(leftChunk, leftIndex);
      let rightTuple = tsplus_module_14.unsafeGet_(rightChunk, rightIndex);
      let k1 = leftTuple.get(0);
      let a = leftTuple.get(1);
      let k2 = rightTuple.get(0);
      let b = rightTuple.get(1);
      let loop = true;

      const hasNext = (c, index) => index < tsplus_module_15.size(c) - 1;

      while (loop) {
        const compare = ord.compare(k1, k2);

        if (compare === 0) {
          builder.append(tsplus_module_2.make(k1, both(a, b)));

          if (hasNext(leftChunk, leftIndex) && hasNext(rightChunk, rightIndex)) {
            leftIndex += 1;
            rightIndex += 1;
            leftTuple = tsplus_module_14.unsafeGet_(leftChunk, leftIndex);
            rightTuple = tsplus_module_14.unsafeGet_(rightChunk, rightIndex);
            k1 = leftTuple.get(0);
            a = leftTuple.get(1);
            k2 = rightTuple.get(0);
            b = rightTuple.get(1);
          } else if (hasNext(leftChunk, leftIndex)) {
            state = new PullRight(tsplus_module_16.drop_(leftChunk, leftIndex + 1));
            loop = false;
          } else if (hasNext(rightChunk, rightIndex)) {
            state = new PullLeft(tsplus_module_16.drop_(rightChunk, rightIndex + 1));
            loop = false;
          } else {
            state = new PullBoth();
            loop = false;
          }
        } else if (compare < 0) {
          builder.append(tsplus_module_2.make(k1, left(a)));

          if (hasNext(leftChunk, leftIndex)) {
            leftIndex += 1;
            leftTuple = tsplus_module_14.unsafeGet_(leftChunk, leftIndex);
            k1 = leftTuple.get(0);
            a = leftTuple.get(1);
          } else {
            const rightBuilder = tsplus_module_13.builder();
            rightBuilder.append(rightTuple);

            while (hasNext(rightChunk, rightIndex)) {
              rightIndex += 1;
              rightTuple = tsplus_module_14.unsafeGet_(rightChunk, rightIndex);
              rightBuilder.append(rightTuple);
              state = new PullLeft(rightBuilder.build());
              loop = false;
            }
          }
        } else {
          builder.append(tsplus_module_2.make(k2, right(b)));

          if (hasNext(rightChunk, rightIndex)) {
            rightIndex += 1;
            rightTuple = tsplus_module_14.unsafeGet_(rightChunk, rightIndex);
            k2 = rightTuple.get(0);
            b = rightTuple.get(1);
          } else {
            const leftBuilder = tsplus_module_13.builder();
            leftBuilder.append(leftTuple);

            while (hasNext(leftChunk, leftIndex)) {
              leftIndex += 1;
              leftTuple = tsplus_module_14.unsafeGet_(leftChunk, leftIndex);
              leftBuilder.append(leftTuple);
              state = new PullRight(leftBuilder.build());
              loop = false;
            }
          }
        }
      }

      return tsplus_module_2.make(builder.build(), state);
    }

    return tsplus_module_17.combineChunks_(self, that, () => new PullBoth(), pull, fileName_1 + ":291:30");
  };
}
/**
 * Zips this stream that is sorted by distinct keys and the specified stream
 * that is sorted by distinct keys to produce a new stream that is sorted by
 * distinct keys. Uses the functions `left`, `right`, and `both` to handle
 * the cases where a key and value exist in this stream, that stream, or
 * both streams.
 *
 * This allows zipping potentially unbounded streams of data by key in
 * constant space but the caller is responsible for ensuring that the
 * streams are sorted by distinct keys.
 *
 * @tsplus static ets/SortedByKey/Aspects zipAllSortedByKeyWith
 */

export const zipAllSortedByKeyWith = ord => self => zipAllSortedByKeyWith_(self, ord);
//# sourceMappingURL=zipAllSortedByKeyWith.mjs.map