"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.bufferTime = void 0;
const Observable_js_1 = require("../Observable.js");
const arrRemove_js_1 = require("../util/arrRemove.js");
const async_js_1 = require("../scheduler/async.js");
const args_js_1 = require("../util/args.js");
const executeSchedule_js_1 = require("../util/executeSchedule.js");
function bufferTime(bufferTimeSpan, ...otherArgs) {
    const scheduler = (0, args_js_1.popScheduler)(otherArgs) ?? async_js_1.asyncScheduler;
    const bufferCreationInterval = otherArgs[0] ?? null;
    const maxBufferSize = otherArgs[1] || Infinity;
    return (source) => new Observable_js_1.Observable((destination) => {
        let bufferRecords = [];
        let restartOnEmit = false;
        const emit = (record) => {
            const { buffer, subs } = record;
            subs.unsubscribe();
            (0, arrRemove_js_1.arrRemove)(bufferRecords, record);
            destination.next(buffer);
            restartOnEmit && startBuffer();
        };
        const startBuffer = () => {
            if (bufferRecords) {
                const subs = new Observable_js_1.Subscription();
                destination.add(subs);
                const buffer = [];
                const record = {
                    buffer,
                    subs,
                };
                bufferRecords.push(record);
                (0, executeSchedule_js_1.executeSchedule)(subs, scheduler, () => emit(record), bufferTimeSpan);
            }
        };
        if (bufferCreationInterval !== null && bufferCreationInterval >= 0) {
            (0, executeSchedule_js_1.executeSchedule)(destination, scheduler, startBuffer, bufferCreationInterval, true);
        }
        else {
            restartOnEmit = true;
        }
        startBuffer();
        const bufferTimeSubscriber = (0, Observable_js_1.operate)({
            destination,
            next: (value) => {
                const recordsCopy = bufferRecords.slice();
                for (const record of recordsCopy) {
                    const { buffer } = record;
                    buffer.push(value);
                    maxBufferSize <= buffer.length && emit(record);
                }
            },
            complete: () => {
                while (bufferRecords?.length) {
                    destination.next(bufferRecords.shift().buffer);
                }
                bufferTimeSubscriber?.unsubscribe();
                destination.complete();
                destination.unsubscribe();
            },
            finalize: () => (bufferRecords = null),
        });
        source.subscribe(bufferTimeSubscriber);
    });
}
exports.bufferTime = bufferTime;