"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.IterableEventQueue = void 0;
const events_1 = require("events");
class IterableEventQueue extends events_1.EventEmitter {
    resolveNext = null;
    queue;
    hasDataListeners;
    drainCloseListener;
    currentDrainResolver = null;
    [Symbol.asyncIterator]() {
        const iterator = new EventQueueIterator();
        iterator.queue = this;
        // @ts-expect-error The EventQueueIterator is acceptable as an AsyncIterator
        return iterator;
    }
    push(message) {
        this.send(message);
    }
    send(message) {
        if (this.resolveNext) {
            this.resolveNext({ value: message });
            this.resolveNext = null;
        }
        else if (this.hasDataListeners) {
            this.emit('data', message);
        }
        else {
            if (!this.queue)
                this.queue = [];
            this.queue.push(message);
        }
    }
    getNextMessage() {
        const message = this.queue?.shift();
        if (!message)
            this.emit('drained');
        return message;
    }
    /**
     * Wait for the queue to be drained, resolving to true to continue or false if the queue was closed before draining.
     */
    waitForDrain() {
        return new Promise((resolve) => {
            if (!this.queue || this.queue.length === 0)
                resolve(true);
            else {
                this.once('drained', () => resolve(true));
                this.currentDrainResolver = resolve;
                if (!this.drainCloseListener) {
                    this.drainCloseListener = true;
                    this.on('close', () => {
                        this.currentDrainResolver?.(false);
                    });
                }
            }
        });
    }
    on(eventName, listener) {
        if (eventName === 'data' && !this.hasDataListeners) {
            this.hasDataListeners = true;
            while (this.queue?.length > 0)
                listener(this.queue.shift());
        }
        return super.on(eventName, listener);
    }
}
exports.IterableEventQueue = IterableEventQueue;
class EventQueueIterator {
    queue;
    push(message) {
        this.queue.send(message);
    }
    // @ts-expect-error TypeScript is wrong, the JS engine accepts MaybePromise<...>
    next() {
        const message = this.queue.getNextMessage();
        if (message) {
            return {
                value: message,
            };
        }
        else {
            return new Promise((resolve) => (this.queue.resolveNext = resolve));
        }
    }
    // @ts-expect-error TypeScript is wrong, the JS engine accepts MaybePromise<...>
    return(value) {
        this.queue.emit('close');
        return {
            value,
            done: true,
        };
    }
    // @ts-expect-error TypeScript is wrong, the JS engine accepts MaybePromise<...>
    throw(error) {
        this.queue.emit('close', error);
        return {
            done: true,
            value: undefined,
        };
    }
}
//# sourceMappingURL=IterableEventQueue.js.map