import * as tsplus_module_1 from "@effect/core/stream/Stream/operations/_internal/HandoffSignal";
import * as tsplus_module_2 from "@effect/core/stream/Stream/operations/_internal/Handoff";
import * as tsplus_module_3 from "@effect/core/stream/Channel/operations/fromEffect";
import * as tsplus_module_4 from "@effect/core/stream/Channel/operations/zipRight";
import * as tsplus_module_5 from "@effect/core/stream/Stream/SinkEndReason";
import * as tsplus_module_6 from "@effect/core/stream/Channel/operations/readWithCause";
import * as tsplus_module_7 from "@tsplus/stdlib/collections/Chunk/isNonEmpty";
import * as tsplus_module_8 from "@effect/core/stream/Channel/operations/write";
import * as tsplus_module_9 from "@effect/core/io/Effect/operations/succeed";
import * as tsplus_module_10 from "@effect/core/io/Effect/operations/zipRight";
import * as tsplus_module_11 from "@effect/core/stream/Channel/operations/failCause";
import * as tsplus_module_12 from "@effect/core/io/Effect/operations/map";
import * as tsplus_module_13 from "@tsplus/stdlib/collections/Chunk/empty";
import * as tsplus_module_14 from "@effect/core/io/Effect/operations/flatMap";
import * as tsplus_module_15 from "@effect/core/stream/Channel/operations/unwrap";
import * as tsplus_module_16 from "@tsplus/stdlib/data/Maybe/definition";
import * as tsplus_module_17 from "@effect/core/io/Effect/operations/forkScoped";
import * as tsplus_module_18 from "@effect/core/stream/Channel/operations/pipeToOrFail";
import * as tsplus_module_19 from "@effect/core/stream/Channel/operations/doneCollect";
import * as tsplus_module_20 from "@effect/core/stream/Channel/operations/runScoped";
import * as tsplus_module_21 from "@effect/core/stream/Channel/operations/pipeTo";
import * as tsplus_module_22 from "@effect/core/stream/Stream/operations/unwrapScoped";
import * as tsplus_module_23 from "@effect/core/io/Ref/operations/make";
import * as tsplus_module_24 from "@effect/core/io/Schedule/operations/driver";
import * as tsplus_module_25 from "@effect/core/io/Effect/operations/tuple";
import * as tsplus_module_26 from "@effect/core/stream/Stream/operations/fromEffect";
import * as tsplus_module_27 from "@effect/core/stream/Stream/operations/flatMap";
import * as tsplus_module_28 from "@tsplus/stdlib/collections/Chunk/flatten";
import * as tsplus_module_29 from "@tsplus/stdlib/data/Either/definition";
import * as tsplus_module_30 from "@tsplus/stdlib/collections/Chunk/single";
import * as tsplus_module_31 from "@tsplus/stdlib/collections/Chunk/make";
import * as tsplus_module_32 from "@tsplus/stdlib/data/Maybe/fold";
import * as tsplus_module_33 from "@effect/core/stream/Channel/operations/unwrapScoped";
import * as tsplus_module_34 from "@effect/core/stream/Channel/operations/unit";
import * as tsplus_module_35 from "@effect/core/io/Fiber/operations/join";
import * as tsplus_module_36 from "@effect/core/io/Fiber/operations/interrupt";
import * as tsplus_module_37 from "@effect/core/io/Effect/operations/done";
import * as tsplus_module_38 from "@effect/core/io/Effect/operations/forkDaemon";
import * as tsplus_module_39 from "@effect/core/io/Cause/operations/failureOrCause";
import * as tsplus_module_40 from "@tsplus/stdlib/data/Either/fold";
import * as tsplus_module_41 from "@effect/core/io/Effect/operations/foldCauseEffect";
import * as tsplus_module_42 from "@effect/core/io/Effect/operations/raceWith";
import { concreteSink } from "@effect/core/stream/Sink/operations/_internal/SinkInternal";
import { concreteStream, StreamInternal } from "@effect/core/stream/Stream/operations/_internal/StreamInternal";
/**
 * Aggregates elements using the provided sink until it completes, or until
 * the delay signalled by the schedule has passed.
 *
 * This operator divides the stream into two asynchronous islands. Operators
 * upstream of this operator run on one fiber, while downstream operators run
 * on another. Elements will be aggregated by the sink until the downstream
 * fiber pulls the aggregated value, or until the schedule's delay has passed.
 *
 * Aggregated elements will be fed into the schedule to determine the delays
 * between pulls.
 *
 * @param sink Used for the aggregation
 * @param schedule Used for signalling for when to stop the aggregation
 *
 * @tsplus fluent ets/Stream aggregateWithinEither
 */

export function aggregateWithinEither_(self, sink, schedule, __tsplusTrace) {
  return tsplus_module_27.flatMap_(tsplus_module_26.fromEffect(() => tsplus_module_25.tuple(tsplus_module_2.make(__tsplusTrace), tsplus_module_23.makeRef(() => tsplus_module_5.scheduleEnd, __tsplusTrace), tsplus_module_23.makeRef(() => tsplus_module_13.empty(), __tsplusTrace), tsplus_module_24.driver(schedule()), tsplus_module_23.makeRef(() => false, __tsplusTrace)), __tsplusTrace), ({
    tuple: [handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed]
  }) => {
    const handoffProducer = tsplus_module_6.readWithCause(input => tsplus_module_4.zipRight_(tsplus_module_3.fromEffect(() => tsplus_module_2.offer(handoff, tsplus_module_1.emit(input), __tsplusTrace)), () => handoffProducer), cause => tsplus_module_3.fromEffect(() => tsplus_module_2.offer(handoff, tsplus_module_1.halt(cause), __tsplusTrace)), () => tsplus_module_3.fromEffect(() => tsplus_module_2.offer(handoff, tsplus_module_1.end(tsplus_module_5.upstreamEnd), __tsplusTrace)));
    const handoffConsumer = tsplus_module_15.unwrap(() => tsplus_module_14.flatMap_(sinkLeftovers.getAndSet(tsplus_module_13.empty(), __tsplusTrace), leftovers => tsplus_module_7.isNonEmpty(leftovers) ? tsplus_module_10.zipRight_(consumed.set(true, __tsplusTrace), () => tsplus_module_9.succeed(() => tsplus_module_4.zipRight_(tsplus_module_8.write(() => leftovers), () => handoffConsumer), __tsplusTrace), __tsplusTrace) : tsplus_module_12.map_(tsplus_module_2.take(handoff, __tsplusTrace), signal => {
      switch (signal._tag) {
        case "Emit":
          {
            return tsplus_module_4.zipRight_(tsplus_module_4.zipRight_(tsplus_module_3.fromEffect(() => consumed.set(true, __tsplusTrace)), () => tsplus_module_8.write(() => signal.elements)), () => handoffConsumer);
          }

        case "Halt":
          {
            return tsplus_module_11.failCause(() => signal.error);
          }

        case "End":
          {
            return signal.reason._tag === "ScheduleEnd" ? tsplus_module_12.map_(consumed.get(__tsplusTrace), p => p ? tsplus_module_3.fromEffect(() => sinkEndReason.set(tsplus_module_5.scheduleEnd, __tsplusTrace)) : tsplus_module_4.zipRight_(tsplus_module_3.fromEffect(() => sinkEndReason.set(tsplus_module_5.scheduleEnd, __tsplusTrace)), () => handoffConsumer), __tsplusTrace) : tsplus_module_3.fromEffect(() => sinkEndReason.set(signal.reason, __tsplusTrace));
          }
      }
    }, __tsplusTrace), __tsplusTrace));
    const sink0 = sink();
    void 0;
    void 0;
    const stream = tsplus_module_14.flatMap_(tsplus_module_17.forkScoped(tsplus_module_20.runScoped(tsplus_module_21.pipeTo_(self.channel, () => handoffProducer)), __tsplusTrace), () => tsplus_module_14.flatMap_(tsplus_module_17.forkScoped(tsplus_module_20.runScoped(tsplus_module_19.doneCollect(tsplus_module_18.pipeToOrFail_(handoffConsumer, () => sink0.channel))), __tsplusTrace), sinkFiber => tsplus_module_12.map_(tsplus_module_17.forkScoped(timeout(scheduleDriver, tsplus_module_16.none), __tsplusTrace), scheduleFiber => new StreamInternal(scheduledAggregator(sink0, handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, handoffProducer, handoffConsumer, sinkFiber, scheduleFiber, __tsplusTrace)), __tsplusTrace), __tsplusTrace), __tsplusTrace);
    return tsplus_module_22.unwrapScoped(() => stream, __tsplusTrace);
  }, __tsplusTrace);
}
/**
 * Aggregates elements using the provided sink until it completes, or until
 * the delay signalled by the schedule has passed.
 *
 * This operator divides the stream into two asynchronous islands. Operators
 * upstream of this operator run on one fiber, while downstream operators run
 * on another. Elements will be aggregated by the sink until the downstream
 * fiber pulls the aggregated value, or until the schedule's delay has passed.
 *
 * Aggregated elements will be fed into the schedule to determine the delays
 * between pulls.
 *
 * @param sink Used for the aggregation
 * @param schedule Used for signalling for when to stop the aggregation
 *
 * @tsplus static ets/Stream/Aspects aggregateWithinEither
 */

export const aggregateWithinEither = (sink, schedule, __tsplusTrace) => self => aggregateWithinEither_(self, sink, schedule, __tsplusTrace);

function timeout(scheduleDriver, last) {
  return scheduleDriver.next(last);
}

function handleSide(sink, handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, handoffProducer, handoffConsumer, forkSink, leftovers, b, c, __tsplusTrace) {
  return tsplus_module_15.unwrap(() => tsplus_module_10.zipRight_(sinkLeftovers.set(tsplus_module_28.flatten(leftovers), __tsplusTrace), () => tsplus_module_12.map_(sinkEndReason.get(__tsplusTrace), reason => {
    switch (reason._tag) {
      case "ScheduleEnd":
        {
          return tsplus_module_33.unwrapScoped(tsplus_module_14.flatMap_(consumed.get(__tsplusTrace), isConsumed => tsplus_module_14.flatMap_(forkSink, sinkFiber => tsplus_module_12.map_(tsplus_module_17.forkScoped(timeout(scheduleDriver, tsplus_module_16.some(b)), __tsplusTrace), scheduleFiber => {
            const toWrite = tsplus_module_32.fold_(c, () => tsplus_module_30.single(tsplus_module_29.right(b)), c => tsplus_module_31.make(tsplus_module_29.right(b), tsplus_module_29.left(c)));
            return isConsumed ? tsplus_module_4.zipRight_(tsplus_module_8.write(() => toWrite), () => scheduledAggregator(sink, handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, handoffProducer, handoffConsumer, sinkFiber, scheduleFiber, __tsplusTrace)) : scheduledAggregator(sink, handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, handoffProducer, handoffConsumer, sinkFiber, scheduleFiber, __tsplusTrace);
          }, __tsplusTrace), __tsplusTrace), __tsplusTrace));
        }

      case "UpstreamEnd":
        {
          return tsplus_module_15.unwrap(() => tsplus_module_12.map_(consumed.get(__tsplusTrace), p => p ? tsplus_module_8.write(() => tsplus_module_30.single(tsplus_module_29.right(b))) : tsplus_module_34.unit, __tsplusTrace));
        }
    }
  }, __tsplusTrace), __tsplusTrace));
}

function scheduledAggregator(sink, handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, handoffProducer, handoffConsumer, sinkFiber, scheduleFiber, __tsplusTrace) {
  void 0;
  const forkSink = tsplus_module_10.zipRight_(consumed.set(false, __tsplusTrace), () => tsplus_module_17.forkScoped(tsplus_module_20.runScoped(tsplus_module_19.doneCollect(tsplus_module_18.pipeToOrFail_(handoffConsumer, () => sink.channel))), __tsplusTrace), __tsplusTrace);
  return tsplus_module_15.unwrap(() => tsplus_module_42.raceWith_(tsplus_module_35.join(sinkFiber, __tsplusTrace), () => tsplus_module_35.join(scheduleFiber, __tsplusTrace), (sinkExit, scheduleFiber) => tsplus_module_10.zipRight_(tsplus_module_36.interrupt(scheduleFiber, __tsplusTrace), () => tsplus_module_12.map_(tsplus_module_37.done(() => sinkExit, __tsplusTrace), ({
    tuple: [leftovers, b]
  }) => handleSide(sink, handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, handoffProducer, handoffConsumer, forkSink, leftovers, b, tsplus_module_16.none, __tsplusTrace), __tsplusTrace), __tsplusTrace), (scheduleExit, sinkFiber) => tsplus_module_41.foldCauseEffect_(tsplus_module_37.done(() => scheduleExit, __tsplusTrace), cause => tsplus_module_40.fold_(tsplus_module_39.failureOrCause(cause), () => tsplus_module_10.zipRight_(tsplus_module_38.forkDaemon(tsplus_module_2.offer(handoff, tsplus_module_1.end(tsplus_module_5.scheduleEnd), __tsplusTrace), __tsplusTrace), () => tsplus_module_12.map_(tsplus_module_35.join(sinkFiber, __tsplusTrace), ({
    tuple: [leftovers, b]
  }) => handleSide(sink, handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, handoffProducer, handoffConsumer, forkSink, leftovers, b, tsplus_module_16.none, __tsplusTrace), __tsplusTrace), __tsplusTrace), cause => tsplus_module_10.zipRight_(tsplus_module_38.forkDaemon(tsplus_module_2.offer(handoff, tsplus_module_1.halt(cause), __tsplusTrace), __tsplusTrace), () => tsplus_module_12.map_(tsplus_module_35.join(sinkFiber, __tsplusTrace), ({
    tuple: [leftovers, b]
  }) => handleSide(sink, handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, handoffProducer, handoffConsumer, forkSink, leftovers, b, tsplus_module_16.none, __tsplusTrace), __tsplusTrace), __tsplusTrace)), c => tsplus_module_10.zipRight_(tsplus_module_38.forkDaemon(tsplus_module_2.offer(handoff, tsplus_module_1.end(tsplus_module_5.scheduleEnd), __tsplusTrace), __tsplusTrace), () => tsplus_module_12.map_(tsplus_module_35.join(sinkFiber, __tsplusTrace), ({
    tuple: [leftovers, b]
  }) => handleSide(sink, handoff, sinkEndReason, sinkLeftovers, scheduleDriver, consumed, handoffProducer, handoffConsumer, forkSink, leftovers, b, tsplus_module_16.some(c), __tsplusTrace), __tsplusTrace), __tsplusTrace), __tsplusTrace), __tsplusTrace));
}
//# sourceMappingURL=aggregateWithinEither.mjs.map