/**
 * Copyright (c) Microsoft Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { RelayConnection, debugLog } from './relayConnection';
class EagerPending {
    _connection;
    onclose;
    static async create(mcpRelayUrl, protocolVersion) {
        const connection = await openRelayConnection(mcpRelayUrl, protocolVersion);
        return new EagerPending(connection);
    }
    constructor(connection) {
        this._connection = connection;
        this._connection.onclose = () => this.onclose?.();
    }
    async connect() {
        return this._connection;
    }
    close(reason) {
        this._connection.close(reason);
    }
}
class DeferredPending {
    _mcpRelayUrl;
    _protocolVersion;
    constructor(_mcpRelayUrl, _protocolVersion) {
        this._mcpRelayUrl = _mcpRelayUrl;
        this._protocolVersion = _protocolVersion;
    }
    async connect() {
        return openRelayConnection(this._mcpRelayUrl, this._protocolVersion);
    }
    close(_reason) {
    }
}
export class PendingConnections {
    _map = new Map();
    constructor() {
        chrome.tabs.onRemoved.addListener(this._onTabRemoved.bind(this));
    }
    // v1 opens the relay WS eagerly — the daemon expects a prompt connection.
    // v2 records only the descriptor; the WS opens lazily in `take` once the
    // user clicks Allow.
    async create(selectorTabId, mcpRelayUrl, protocolVersion) {
        if (protocolVersion !== 1) {
            this._map.set(selectorTabId, new DeferredPending(mcpRelayUrl, protocolVersion));
            return;
        }
        const entry = await EagerPending.create(mcpRelayUrl, protocolVersion);
        entry.onclose = () => {
            if (this._map.get(selectorTabId) !== entry)
                return;
            this._map.delete(selectorTabId);
            chrome.tabs.sendMessage(selectorTabId, { type: 'pendingConnectionClosed' }).catch(() => { });
        };
        this._map.set(selectorTabId, entry);
    }
    async take(selectorTabId) {
        const entry = this._map.get(selectorTabId);
        if (!entry)
            return undefined;
        this._map.delete(selectorTabId);
        return entry.connect();
    }
    _onTabRemoved(tabId) {
        const entry = this._map.get(tabId);
        if (!entry)
            return;
        this._map.delete(tabId);
        entry.close('Browser tab closed');
    }
}
async function openRelayConnection(mcpRelayUrl, protocolVersion) {
    try {
        const socket = new WebSocket(mcpRelayUrl);
        await new Promise((resolve, reject) => {
            socket.onopen = () => resolve();
            socket.onerror = () => reject(new Error('WebSocket error'));
            setTimeout(() => reject(new Error('Connection timeout')), 5000);
        });
        return new RelayConnection(socket, protocolVersion);
    }
    catch (error) {
        const message = `Failed to connect to MCP relay: ${error.message}`;
        debugLog(message);
        throw new Error(message);
    }
}
//# sourceMappingURL=pendingConnection.js.map