"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.mergeGroupBy = exports.mergeGroupBy_ = exports.first = exports.first_ = exports.filter = exports.filter_ = exports.make = exports.make_ = exports.GroupBy = void 0;
const tracing_1 = __importStar(require("../../../Tracing"));
const fileName_1 = "(@effect-ts/system): _src/Experimental/Stream/GroupBy/GroupBy.ts";
const Mp = __importStar(require("../../../Collections/Immutable/Map"));
const Tp = __importStar(require("../../../Collections/Immutable/Tuple"));
const T = __importStar(require("../../../Effect"));
const Ex = __importStar(require("../../../Exit"));
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 ChainPar = __importStar(require("../_internal/api/chainPar"));
const DistributedWithDynamic = __importStar(require("../_internal/api/distributedWithDynamic"));
const FilterEffect = __importStar(require("../_internal/api/filterEffect"));
const FlattenExitOption = __importStar(require("../_internal/api/flattenExitOption"));
const FromQueueWithShutdown = __importStar(require("../_internal/api/fromQueueWithShutdown"));
const Map = __importStar(require("../_internal/api/map"));
const MapEffect = __importStar(require("../_internal/api/mapEffect"));
const UnwrapManaged = __importStar(require("../_internal/api/unwrapManaged"));
const ZipWithIndex = __importStar(require("../_internal/api/zipWithIndex"));
class GroupBy {
}
exports.GroupBy = GroupBy;
class GroupByInternal extends GroupBy {
    constructor(stream, key, buffer) {
        super();
        this.stream = stream;
        this.key = key;
        this.buffer = buffer;
        this.grouped = UnwrapManaged.unwrapManaged((M.map_(M.tap_(M.bind_(M.bind_(M.bind_(M.bind_(M.do, "decider", () => T.toManaged(P.make()), fileName_1 + ":45:13"), "out", () => T.toManagedRelease_(Q.makeBounded(this.buffer, fileName_1 + ":50:24"), Q.shutdown), fileName_1 + ":48:13"), "ref", () => T.toManaged(Ref.makeRef(Mp.empty)), fileName_1 + ":56:13"), "add", ({ decider, out }) => (DistributedWithDynamic.distributedWithDynamic_(MapEffect.mapEffect_(this.stream, this.key), this.buffer, ({ tuple: [k, v] }) => T.chain_(P.await(decider), (_) => _(k, v), fileName_1 + ":64:23"), (_) => Q.offer_(out, _))), fileName_1 + ":57:13"), ({ add, decider, out, ref }) => T.toManaged(P.succeed_(decider, (k, _) => (T.chain_(T.map_(ref.get, Mp.lookup(k), fileName_1 + ":74:20"), O.fold(() => T.chain_(add, ({ tuple: [idx, q] }) => T.as_(T.zipRight_(Ref.update_(ref, Mp.insert(k, idx)), Q.offer_(out, Ex.succeed(Tp.tuple(k, Q.map_(q, Ex.map(({ tuple: [_, a] }) => a))))), fileName_1 + ":80:36"), (_) => _ === idx, fileName_1 + ":79:28"), fileName_1 + ":78:29"), (idx) => T.succeed((_) => _ === idx, fileName_1 + ":98:37")), fileName_1 + ":75:22")))), fileName_1 + ":69:12"), ({ out }) => FlattenExitOption.flattenExitOption(FromQueueWithShutdown.fromQueueWithShutdown_(out)), fileName_1 + ":105:12")));
    }
    /**
     * Only consider the first n groups found in the stream.
     */
    first(n) {
        return new FirstInternal(this.stream, this.key, this.buffer, n);
    }
    /**
     * Only consider the first n groups found in the stream.
     */
    filter(f) {
        return new FilterInternal(this.stream, this.key, this.buffer, f);
    }
    apply(f) {
        return ChainPar.chainPar_(this.grouped, Number.MAX_SAFE_INTEGER, ({ tuple: [k, q] }) => f(k, FlattenExitOption.flattenExitOption(FromQueueWithShutdown.fromQueueWithShutdown_(q))));
    }
}
class FirstInternal extends GroupByInternal {
    constructor(stream, key, buffer, n) {
        super(stream, key, buffer);
        this.n = n;
        this.grouped = (Map.map_(FilterEffect.filterEffect_(ZipWithIndex.zipWithIndex(super.grouped), (elem) => {
            const { tuple: [{ tuple: [_, q] }, i] } = elem;
            return i < this.n ? T.as_(T.succeed(elem, fileName_1 + ":167:42"), true, fileName_1 + ":167:32") : T.as_(Q.shutdown(q), false, fileName_1 + ":167:63");
        }), Tp.get(0)));
    }
}
class FilterInternal extends GroupByInternal {
    constructor(stream, key, buffer, f) {
        super(stream, key, buffer);
        this.f = f;
        this.grouped = (FilterEffect.filterEffect_(super.grouped, (elem) => {
            const { tuple: [k, q] } = elem;
            return this.f(k) ? T.as_(T.succeed(elem, fileName_1 + ":190:41"), true, fileName_1 + ":190:31") : T.as_(Q.shutdown(q), false, fileName_1 + ":190:62");
        }));
    }
}
function concrete(_groupBy) {
    //
}
function make_(stream, key, buffer) {
    return new GroupByInternal(stream, key, buffer);
}
exports.make_ = make_;
/**
 * @ets_data_first make_
 */
function make(key, buffer) {
    return (stream) => make_(stream, key, buffer);
}
exports.make = make;
/**
 * Only consider the first n groups found in the stream.
 */
function filter_(self, f) {
    concrete(self);
    return self.filter(f);
}
exports.filter_ = filter_;
/**
 * Only consider the first n groups found in the stream.
 *
 * @ets_data_first filter_
 */
function filter(f) {
    return (self) => filter_(self, f);
}
exports.filter = filter;
/**
 * Only consider the first n groups found in the stream.
 */
function first_(self, n) {
    concrete(self);
    return self.first(n);
}
exports.first_ = first_;
/**
 * Only consider the first n groups found in the stream.
 *
 * @ets_data_first first_
 */
function first(n) {
    return (self) => first_(self, n);
}
exports.first = first;
function mergeGroupBy_(self, f) {
    concrete(self);
    return self.apply(f);
}
exports.mergeGroupBy_ = mergeGroupBy_;
/**
 * @ets_data_first mergeGroupBy_
 */
function mergeGroupBy(f) {
    return (self) => mergeGroupBy_(self, f);
}
exports.mergeGroupBy = mergeGroupBy;
//# sourceMappingURL=GroupBy.js.map