import { isDefined, UUID } from "@opendaw/lib-std";
const MAX_MONITORING_CHANNELS = 8;
export class MonitoringRouter {
    #context;
    #worklet;
    #commands;
    #splitter;
    #sources = UUID.newSet(entry => entry.uuid);
    #inputMerger = null;
    #outputMergers = [];
    constructor(worklet, commands) {
        this.#context = worklet.context;
        this.#worklet = worklet;
        this.#commands = commands;
        this.#splitter = this.#context.createChannelSplitter(MAX_MONITORING_CHANNELS);
        worklet.connect(this.#splitter, 1);
    }
    registerSource(uuid, sourceNode, numChannels, destinationNode) {
        this.#sources.add({ uuid, sourceNode, numChannels, destinationNode }, true);
        this.#rebuild();
    }
    unregisterSource(uuid) {
        this.#sources.removeByKeyIfExist(uuid);
        this.#rebuild();
    }
    #rebuild() {
        if (isDefined(this.#inputMerger)) {
            this.#inputMerger.disconnect();
            this.#inputMerger = null;
        }
        for (const merger of this.#outputMergers) {
            merger.disconnect();
        }
        this.#outputMergers = [];
        if (this.#sources.isEmpty()) {
            this.#commands.updateMonitoringMap([]);
            return;
        }
        let totalChannels = 0;
        for (const { numChannels } of this.#sources) {
            totalChannels += numChannels;
        }
        if (totalChannels > MAX_MONITORING_CHANNELS) {
            console.warn(`MonitoringRouter: ${totalChannels} channels requested, max is ${MAX_MONITORING_CHANNELS}. Some sources will not receive effects monitoring.`);
        }
        const usedChannels = Math.min(totalChannels, MAX_MONITORING_CHANNELS);
        this.#inputMerger = this.#context.createChannelMerger(usedChannels);
        this.#inputMerger.connect(this.#worklet);
        const map = [];
        let channel = 0;
        for (const { uuid, sourceNode, numChannels, destinationNode } of this.#sources) {
            if (channel + numChannels > MAX_MONITORING_CHANNELS) {
                break;
            }
            const inputSplitter = this.#context.createChannelSplitter(numChannels);
            sourceNode.connect(inputSplitter);
            const channels = [];
            for (let i = 0; i < numChannels; i++) {
                inputSplitter.connect(this.#inputMerger, i, channel);
                channels.push(channel);
                channel++;
            }
            map.push({ uuid, channels });
            const outputMerger = this.#context.createChannelMerger(2);
            if (numChannels === 2) {
                this.#splitter.connect(outputMerger, channels[0], 0);
                this.#splitter.connect(outputMerger, channels[1], 1);
            }
            else {
                this.#splitter.connect(outputMerger, channels[0], 0);
                this.#splitter.connect(outputMerger, channels[0], 1);
            }
            outputMerger.connect(destinationNode);
            this.#outputMergers.push(outputMerger);
        }
        this.#commands.updateMonitoringMap(map);
    }
    terminate() {
        if (isDefined(this.#inputMerger)) {
            this.#inputMerger.disconnect();
            this.#inputMerger = null;
        }
        for (const merger of this.#outputMergers) {
            merger.disconnect();
        }
        this.#outputMergers = [];
        this.#sources.clear();
    }
}
