import { EMPTY, Observable } from "rxjs";
/**
 * Like `combineLatest` but with some differences:
 *
 * - It only works on arrays as an input
 * - Batches updates to each array index that contains a referentially equal
 *   observable
 * - Doesn't allow for custom scheduler
 * - Expects array of constructed observables instead of `Array<ObservableInput>`
 */
export function combineLatestBatched(observables) {
    if (observables.length === 0) {
        return EMPTY;
    }
    return new Observable((observer) => {
        const { length } = observables;
        // Keeps track of current values for each observable
        const values = new Array(length);
        // Used to batch an update each item in the array that share an observable
        // so that they can be emitted together.
        const indexesByObservable = new Map();
        observables.forEach((source, idx) => {
            if (!indexesByObservable.has(source)) {
                indexesByObservable.set(source, new Set());
            }
            indexesByObservable.get(source).add(idx);
        });
        // Track the number of active subscriptions so we know when to complete this
        // observable
        let active = indexesByObservable.size;
        // Track how many observables are left to emit their first value
        let remainingFirstValues = indexesByObservable.size;
        let currentBatch;
        // Subscribe to each unique observable instead of the raw source array of
        // observables since we want at most 1-subscription per unique observable.
        // This ensures an update can write to multiple indexes before emitting the
        // result.
        indexesByObservable.forEach((indexes, source) => {
            let hasFirstValue = false;
            const subscription = source.subscribe({
                next: (value) => {
                    indexes.forEach((idx) => (values[idx] = value));
                    if (!hasFirstValue) {
                        hasFirstValue = true;
                        remainingFirstValues--;
                    }
                    if (!remainingFirstValues) {
                        currentBatch ||= new Set(observables.filter((obs) => obs.dirty));
                        currentBatch.delete(source);
                        if (!currentBatch.size) {
                            observer.next(values.slice());
                            currentBatch = undefined;
                        }
                    }
                },
                complete: () => {
                    active--;
                    if (!active) {
                        observer.complete();
                    }
                },
                error: observer.error.bind(observer),
            });
            observer.add(subscription);
        });
    });
}
//# sourceMappingURL=combineLatestBatched.js.map