/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { detectIde, getIdeDisplayName, } from '../ide/detect-ide.js';
import { ideContext, IdeContextNotificationSchema } from '../ide/ideContext.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
const logger = {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    debug: (...args) => console.debug('[DEBUG] [IDEClient]', ...args),
};
export var IDEConnectionStatus;
(function (IDEConnectionStatus) {
    IDEConnectionStatus["Connected"] = "connected";
    IDEConnectionStatus["Disconnected"] = "disconnected";
    IDEConnectionStatus["Connecting"] = "connecting";
})(IDEConnectionStatus || (IDEConnectionStatus = {}));
/**
 * Manages the connection to and interaction with the IDE server.
 */
export class IdeClient {
    static instance;
    client = undefined;
    state = {
        status: IDEConnectionStatus.Disconnected,
        details: 'IDE integration is currently disabled. To enable it, run /ide enable.',
    };
    currentIde;
    currentIdeDisplayName;
    constructor() {
        this.currentIde = detectIde();
        if (this.currentIde) {
            this.currentIdeDisplayName = getIdeDisplayName(this.currentIde);
        }
    }
    static getInstance() {
        if (!IdeClient.instance) {
            IdeClient.instance = new IdeClient();
        }
        return IdeClient.instance;
    }
    async connect() {
        this.setState(IDEConnectionStatus.Connecting);
        if (!this.currentIde || !this.currentIdeDisplayName) {
            this.setState(IDEConnectionStatus.Disconnected);
            return;
        }
        if (!this.validateWorkspacePath()) {
            return;
        }
        const port = this.getPortFromEnv();
        if (!port) {
            return;
        }
        await this.establishConnection(port);
    }
    disconnect() {
        this.setState(IDEConnectionStatus.Disconnected, 'IDE integration disabled. To enable it again, run /ide enable.');
        this.client?.close();
    }
    getCurrentIde() {
        return this.currentIde;
    }
    getConnectionStatus() {
        return this.state;
    }
    setState(status, details) {
        const isAlreadyDisconnected = this.state.status === IDEConnectionStatus.Disconnected &&
            status === IDEConnectionStatus.Disconnected;
        // Only update details if the state wasn't already disconnected, so that
        // the first detail message is preserved.
        if (!isAlreadyDisconnected) {
            this.state = { status, details };
        }
        if (status === IDEConnectionStatus.Disconnected) {
            logger.debug('IDE integration disconnected:', details);
            ideContext.clearIdeContext();
        }
    }
    validateWorkspacePath() {
        const ideWorkspacePath = process.env['GEMINI_CLI_IDE_WORKSPACE_PATH'];
        if (ideWorkspacePath === undefined) {
            this.setState(IDEConnectionStatus.Disconnected, `Failed to connect to IDE companion extension for ${this.currentIdeDisplayName}. Please ensure the extension is running and try refreshing your terminal. To install the extension, run /ide install.`);
            return false;
        }
        if (ideWorkspacePath === '') {
            this.setState(IDEConnectionStatus.Disconnected, `To use this feature, please open a single workspace folder in ${this.currentIdeDisplayName} and try again.`);
            return false;
        }
        if (ideWorkspacePath !== process.cwd()) {
            this.setState(IDEConnectionStatus.Disconnected, `Directory mismatch. Gemini CLI is running in a different location than the open workspace in ${this.currentIdeDisplayName}. Please run the CLI from the same directory as your project's root folder.`);
            return false;
        }
        return true;
    }
    getPortFromEnv() {
        const port = process.env['GEMINI_CLI_IDE_SERVER_PORT'];
        if (!port) {
            this.setState(IDEConnectionStatus.Disconnected, `Failed to connect to IDE companion extension for ${this.currentIdeDisplayName}. Please ensure the extension is running and try refreshing your terminal. To install the extension, run /ide install.`);
            return undefined;
        }
        return port;
    }
    registerClientHandlers() {
        if (!this.client) {
            return;
        }
        this.client.setNotificationHandler(IdeContextNotificationSchema, (notification) => {
            ideContext.setIdeContext(notification.params);
        });
        this.client.onerror = (_error) => {
            this.setState(IDEConnectionStatus.Disconnected, `IDE connection error. The connection was lost unexpectedly. Please try reconnecting by running /ide enable`);
        };
        this.client.onclose = () => {
            this.setState(IDEConnectionStatus.Disconnected, `IDE connection error. The connection was lost unexpectedly. Please try reconnecting by running /ide enable`);
        };
    }
    async establishConnection(port) {
        let transport;
        try {
            this.client = new Client({
                name: 'streamable-http-client',
                // TODO(#3487): use the CLI version here.
                version: '1.0.0',
            });
            transport = new StreamableHTTPClientTransport(new URL(`http://localhost:${port}/mcp`));
            this.registerClientHandlers();
            await this.client.connect(transport);
            this.registerClientHandlers();
            this.setState(IDEConnectionStatus.Connected);
        }
        catch (_error) {
            this.setState(IDEConnectionStatus.Disconnected, `Failed to connect to IDE companion extension for ${this.currentIdeDisplayName}. Please ensure the extension is running and try refreshing your terminal. To install the extension, run /ide install.`);
            if (transport) {
                try {
                    await transport.close();
                }
                catch (closeError) {
                    logger.debug('Failed to close transport:', closeError);
                }
            }
        }
    }
    async init() {
        if (this.state.status === IDEConnectionStatus.Connected) {
            return;
        }
        if (!this.currentIde) {
            this.setState(IDEConnectionStatus.Disconnected, 'Not running in a supported IDE, skipping connection.');
            return;
        }
        this.setState(IDEConnectionStatus.Connecting);
        if (!this.validateWorkspacePath()) {
            return;
        }
        const port = this.getPortFromEnv();
        if (!port) {
            return;
        }
        await this.establishConnection(port);
    }
    dispose() {
        this.client?.close();
    }
    getDetectedIdeDisplayName() {
        return this.currentIdeDisplayName;
    }
    setDisconnected() {
        this.setState(IDEConnectionStatus.Disconnected);
    }
}
//# sourceMappingURL=ide-client.js.map