// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
import { PlayerPresence } from "@foxglove/studio-base/players/types";
import { FoxgloveWebSocketAdapter } from "./adapter.js";
import { FoxgloveConnection } from "./foxglove-connection.js";
import { WebRtcBridge } from "./webrtc/bridge.js";
import { ConfigStore } from "../utils/config-store";
import { Logger } from "../utils/logger";
const logger = Logger.getLogger();
export class VisualizerConnection extends FoxgloveConnection {
    #url = null;
    #config = null;
    #adapter;
    #eventListeners = [];
    constructor({ type, data, errorCallback, debugLogs, messageHandlerVersion }) {
        super(type === "ws" ? data.connectionUrl : data.config.clientId);
        let worker;
        if (type === "ws") {
            this.#url = data.connectionUrl;
            worker = new Worker(new URL("./ws/worker", import.meta.url), { type: "module" });
        }
        else {
            this.#config = data.config;
            worker = new WebRtcBridge(data.automaticTokenRefresh);
        }
        ConfigStore.getInstance().connectionConfigValue = { debugLogs: debugLogs ?? false, messageHandlerVersion: messageHandlerVersion ?? 'v1' };
        ConfigStore.writeToLocalStorage(); // We need this to propagate the config to non-lib code
        logger.info("[VisualizerConnection] - Opening connection with following configuration", ConfigStore.getInstance().connectionConfigValue);
        this.#open(worker, errorCallback);
    }
    close() {
        // Clean up event listeners before closing
        this.#cleanupEventListeners();
        this.#adapter?.close();
        // Clean up message handler workers
        this.messageHandler.cleanup();
        // Clean up pointcloud worker pool
        this.depthToPointcloudWorkerPool.destroy();
    }
    #cleanupEventListeners() {
        if (this.#adapter) {
            for (const { name, listener } of this.#eventListeners) {
                this.#adapter.removeEventListener(name, listener);
            }
            this.#eventListeners = [];
        }
    }
    on(name, listener) {
        this.#adapter?.on(name, listener);
    }
    off(name, listener) {
        this.#adapter?.off(name, listener);
    }
    async request(args) {
        const response = await this.#adapter?.request(args);
        return response ?? null;
    }
    subscribe(args) {
        this.#adapter?.subscribe(args);
        for (const topic of args.topics) {
            this.subscribedTopics.set(topic, topic);
        }
    }
    unsubscribe(args) {
        this.#adapter?.unsubscribe(args);
    }
    // eslint-disable-next-line no-restricted-syntax
    get connected() {
        return Boolean(this.#adapter?.readyState === WebSocket.OPEN);
    }
    #open = (worker, errorCallback) => {
        this.#adapter = new FoxgloveWebSocketAdapter({ wsUrl: this.#url, config: this.#config }, worker);
        const openListener = (() => {
            this.playerPresence = PlayerPresence.PRESENT;
            this.emitState();
        });
        const closeListener = (() => {
            this.playerPresence = PlayerPresence.NOT_PRESENT;
            this.emitState();
            this.#cleanupEventListeners();
            // Clean up message handler workers on close
            this.messageHandler.cleanup();
            // Clean up pointcloud worker pool
            this.depthToPointcloudWorkerPool.destroy();
        });
        const errorListener = ((_event) => {
            this.messageEvents = [];
            this.playerPresence = PlayerPresence.ERROR;
            this.emitState();
            this.#cleanupEventListeners();
            // Close adapter to terminate worker and clean up resources
            this.#adapter?.close();
            // Clean up message handler workers on error
            this.messageHandler.cleanup();
            // Clean up pointcloud worker pool
            this.depthToPointcloudWorkerPool.destroy();
        });
        const wrappedErrorCallback = (errorCode, topic, errorData) => {
            const shouldForwardError = this.handleDeserializationError(errorCode, topic, errorData);
            if (shouldForwardError) {
                errorCallback?.(errorCode, topic, errorData);
            }
        };
        const messageListener = ((event) => {
            this.onMessagePacket.bind(this)(event, wrappedErrorCallback);
        });
        this.#adapter.addEventListener("open", openListener);
        this.#adapter.addEventListener("close", closeListener);
        this.#adapter.addEventListener("error", errorListener);
        this.#adapter.addEventListener("message", messageListener);
        this.#eventListeners = [
            { name: "open", listener: openListener },
            { name: "close", listener: closeListener },
            { name: "error", listener: errorListener },
            { name: "message", listener: messageListener },
        ];
    };
}
//# sourceMappingURL=connection.js.map