"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergeAllWith = exports.mergeAllWith_ = void 0;
// ets_tracing: off
const T = __importStar(require("../../../../Effect"));
const E = __importStar(require("../../../../Either"));
const F = __importStar(require("../../../../Fiber"));
const Function_1 = require("../../../../Function");
const M = __importStar(require("../../../../Managed"));
const O = __importStar(require("../../../../Option"));
const P = __importStar(require("../../../../Promise"));
const Q = __importStar(require("../../../../Queue"));
const Ref = __importStar(require("../../../../Ref"));
const SM = __importStar(require("../../../../Semaphore"));
const C = __importStar(require("../core"));
const Managed = __importStar(require("./managed"));
const ToPull = __importStar(require("./toPull"));
const Unwrap = __importStar(require("./unwrap"));
const ZipRight = __importStar(require("./zipRight"));
function mergeAllWith_(channels, n, f, bufferSize = 16, mergeStrategy = "BackPressure") {
    return Managed.managed_(M.withChildren((getChildren) => (M.map_(M.tap_(M.let_(M.bind_(M.bind_(M.bind_(M.bind_(M.bind_(M.bind_(M.tap_(M.do, () => M.finalizer(T.chain_(getChildren, F.interruptAll))), "queue", () => T.toManagedRelease_(Q.makeBounded(bufferSize), Q.shutdown)), "cancelers", () => T.toManagedRelease_(Q.makeUnbounded(), Q.shutdown)), "lastDone", () => Ref.makeManagedRef(O.none)), "errorSignal", () => P.makeManaged()), "permits", () => T.toManaged(SM.makeSemaphore(n))), "pull", () => ToPull.toPull(channels)), "evaluatePull", ({ errorSignal, lastDone, queue }) => (pull) => (T.catchAllCause_(T.chain_(T.repeatUntil_(T.chain_(pull, E.fold((done) => T.succeed(O.some(done)), (outElem) => T.as_(Q.offer_(queue, T.succeed(E.right(outElem))), O.none))), O.isSome), O.fold(() => T.unit, (outDone) => Ref.update_(lastDone, O.fold(() => O.some(outDone), (lastDone) => O.some(f(lastDone, outDone)))))), (cause) => T.zipRight_(Q.offer_(queue, T.halt(cause)), T.asUnit(P.succeed_(errorSignal, undefined)))))), ({ cancelers, errorSignal, evaluatePull, lastDone, permits, pull, queue }) => (T.forkManaged(T.repeatWhile_(T.foldCauseM_(pull, (cause) => T.zipRight_(T.chain_(getChildren, F.interruptAll), T.as_(Q.offer_(queue, T.halt(cause)), false)), E.fold((outDone) => T.raceWith_(P.await(errorSignal), SM.withPermits_(T.unit, permits, n), (_, permitAcquisition) => T.zipRight_(T.chain_(getChildren, F.interruptAll), T.as_(F.interrupt(permitAcquisition), false)), (_, failureAwait) => T.zipRight_(F.interrupt(failureAwait), T.as_(T.chain_(lastDone.get, O.fold(() => Q.offer_(queue, T.succeed(E.left(outDone))), (lastDone) => Q.offer_(queue, T.succeed(E.left(f(lastDone, outDone)))))), false))), (channel) => {
        if (mergeStrategy === "BackPressure") {
            return (T.map_(T.bind_(T.tap_(T.tap_(T.let_(T.bind_(T.do, "latch", () => P.make()), "raceIOs", () => M.use_(ToPull.toPull(channel), (_) => T.race_(evaluatePull(_), P.await(errorSignal)))), ({ latch, raceIOs }) => T.fork(SM.withPermit_(T.zipRight_(P.succeed_(latch, undefined), raceIOs), permits))), ({ latch }) => P.await(latch)), "errored", () => P.isDone(errorSignal)), ({ errored }) => !errored));
        }
        else {
            return (T.map_(T.bind_(T.tap_(T.tap_(T.let_(T.tap_(T.tap_(T.bind_(T.bind_(T.bind_(T.do, "canceler", () => P.make()), "latch", () => P.make()), "size", () => Q.size(cancelers)), ({ size }) => T.when_(T.chain_(Q.take(cancelers), (_) => P.succeed_(_, undefined)), () => size >= n)), ({ canceler }) => Q.offer_(cancelers, canceler)), "raceIOs", ({ canceler }) => M.use_(ToPull.toPull(channel), (_) => T.race_(T.race_(evaluatePull(_), P.await(errorSignal)), P.await(canceler)))), ({ latch, raceIOs }) => T.fork(SM.withPermit_(T.zipRight_(P.succeed_(latch, undefined), raceIOs), permits))), ({ latch }) => P.await(latch)), "errored", () => P.isDone(errorSignal)), ({ errored }) => !errored));
        }
    })), (x) => x === true)))), ({ queue }) => queue))), (queue) => {
        const consumer = Unwrap.unwrap((T.foldCause_(T.flatten(Q.take(queue)), (cause) => C.failCause(cause), E.fold((outDone) => C.end(outDone), (outElem) => ZipRight.zipRight_(C.write(outElem), consumer)))));
        return consumer;
    });
}
exports.mergeAllWith_ = mergeAllWith_;
/**
 * @ets_data_first mergeAllWith_
 */
function mergeAllWith(n, f, bufferSize = 16, mergeStrategy = "BackPressure") {
    return (channels) => mergeAllWith_(channels, n, f, bufferSize, mergeStrategy);
}
exports.mergeAllWith = mergeAllWith;
//# sourceMappingURL=mergeAllWith.js.map