/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { CommandKind } from './types.js';
import { DiscoveredMCPTool, getMCPDiscoveryState, getMCPServerStatus, MCPDiscoveryState, MCPServerStatus, getErrorMessage, MCPOAuthTokenStorage, } from 'sixth-cli-core';
import { appEvents, AppEvent } from '../../utils/events.js';
import { MessageType } from '../types.js';
const authCommand = {
    name: 'auth',
    description: 'Authenticate with an OAuth-enabled MCP server',
    kind: CommandKind.BUILT_IN,
    action: async (context, args) => {
        const serverName = args.trim();
        const { config } = context.services;
        if (!config) {
            return {
                type: 'message',
                messageType: 'error',
                content: 'Config not loaded.',
            };
        }
        const mcpServers = config.getMcpServers() || {};
        if (!serverName) {
            // List servers that support OAuth
            const oauthServers = Object.entries(mcpServers)
                .filter(([_, server]) => server.oauth?.enabled)
                .map(([name, _]) => name);
            if (oauthServers.length === 0) {
                return {
                    type: 'message',
                    messageType: 'info',
                    content: 'No MCP servers configured with OAuth authentication.',
                };
            }
            return {
                type: 'message',
                messageType: 'info',
                content: `MCP servers with OAuth authentication:\n${oauthServers.map((s) => `  - ${s}`).join('\n')}\n\nUse /mcp auth <server-name> to authenticate.`,
            };
        }
        const server = mcpServers[serverName];
        if (!server) {
            return {
                type: 'message',
                messageType: 'error',
                content: `MCP server '${serverName}' not found.`,
            };
        }
        // Always attempt OAuth authentication, even if not explicitly configured
        // The authentication process will discover OAuth requirements automatically
        const displayListener = (message) => {
            context.ui.addItem({ type: 'info', text: message }, Date.now());
        };
        appEvents.on(AppEvent.OauthDisplayMessage, displayListener);
        try {
            context.ui.addItem({
                type: 'info',
                text: `Starting OAuth authentication for MCP server '${serverName}'...`,
            }, Date.now());
            // Import dynamically to avoid circular dependencies
            const { MCPOAuthProvider } = await import('sixth-cli-core');
            let oauthConfig = server.oauth;
            if (!oauthConfig) {
                oauthConfig = { enabled: false };
            }
            const mcpServerUrl = server.httpUrl || server.url;
            const authProvider = new MCPOAuthProvider(new MCPOAuthTokenStorage());
            await authProvider.authenticate(serverName, oauthConfig, mcpServerUrl, appEvents);
            context.ui.addItem({
                type: 'info',
                text: `✅ Successfully authenticated with MCP server '${serverName}'!`,
            }, Date.now());
            // Trigger tool re-discovery to pick up authenticated server
            const toolRegistry = config.getToolRegistry();
            if (toolRegistry) {
                context.ui.addItem({
                    type: 'info',
                    text: `Re-discovering tools from '${serverName}'...`,
                }, Date.now());
                await toolRegistry.discoverToolsForServer(serverName);
            }
            // Update the client with the new tools
            const geminiClient = config.getGeminiClient();
            if (geminiClient) {
                await geminiClient.setTools();
            }
            // Reload the slash commands to reflect the changes.
            context.ui.reloadCommands();
            return {
                type: 'message',
                messageType: 'info',
                content: `Successfully authenticated and refreshed tools for '${serverName}'.`,
            };
        }
        catch (error) {
            return {
                type: 'message',
                messageType: 'error',
                content: `Failed to authenticate with MCP server '${serverName}': ${getErrorMessage(error)}`,
            };
        }
        finally {
            appEvents.removeListener(AppEvent.OauthDisplayMessage, displayListener);
        }
    },
    completion: async (context, partialArg) => {
        const { config } = context.services;
        if (!config)
            return [];
        const mcpServers = config.getMcpServers() || {};
        return Object.keys(mcpServers).filter((name) => name.startsWith(partialArg));
    },
};
const listAction = async (context, showDescriptions = false, showSchema = false) => {
    const { config } = context.services;
    if (!config) {
        return {
            type: 'message',
            messageType: 'error',
            content: 'Config not loaded.',
        };
    }
    const toolRegistry = config.getToolRegistry();
    if (!toolRegistry) {
        return {
            type: 'message',
            messageType: 'error',
            content: 'Could not retrieve tool registry.',
        };
    }
    const mcpServers = config.getMcpServers() || {};
    const serverNames = Object.keys(mcpServers);
    const blockedMcpServers = config.getBlockedMcpServers() || [];
    const connectingServers = serverNames.filter((name) => getMCPServerStatus(name) === MCPServerStatus.CONNECTING);
    const discoveryState = getMCPDiscoveryState();
    const discoveryInProgress = discoveryState === MCPDiscoveryState.IN_PROGRESS ||
        connectingServers.length > 0;
    const allTools = toolRegistry.getAllTools();
    const mcpTools = allTools.filter((tool) => tool instanceof DiscoveredMCPTool);
    const promptRegistry = await config.getPromptRegistry();
    const mcpPrompts = promptRegistry
        .getAllPrompts()
        .filter((prompt) => 'serverName' in prompt &&
        serverNames.includes(prompt.serverName));
    const authStatus = {};
    const tokenStorage = new MCPOAuthTokenStorage();
    for (const serverName of serverNames) {
        const server = mcpServers[serverName];
        if (server.oauth?.enabled) {
            const creds = await tokenStorage.getCredentials(serverName);
            if (creds) {
                if (creds.token.expiresAt && creds.token.expiresAt < Date.now()) {
                    authStatus[serverName] = 'expired';
                }
                else {
                    authStatus[serverName] = 'authenticated';
                }
            }
            else {
                authStatus[serverName] = 'unauthenticated';
            }
        }
        else {
            authStatus[serverName] = 'not-configured';
        }
    }
    const mcpStatusItem = {
        type: MessageType.MCP_STATUS,
        servers: mcpServers,
        tools: mcpTools.map((tool) => ({
            serverName: tool.serverName,
            name: tool.name,
            description: tool.description,
            schema: tool.schema,
        })),
        prompts: mcpPrompts.map((prompt) => ({
            serverName: prompt.serverName,
            name: prompt.name,
            description: prompt.description,
        })),
        authStatus,
        blockedServers: blockedMcpServers,
        discoveryInProgress,
        connectingServers,
        showDescriptions,
        showSchema,
    };
    context.ui.addItem(mcpStatusItem, Date.now());
};
const listCommand = {
    name: 'list',
    altNames: ['ls', 'nodesc', 'nodescription'],
    description: 'List configured MCP servers and tools',
    kind: CommandKind.BUILT_IN,
    action: (context) => listAction(context),
};
const descCommand = {
    name: 'desc',
    altNames: ['description'],
    description: 'List configured MCP servers and tools with descriptions',
    kind: CommandKind.BUILT_IN,
    action: (context) => listAction(context, true),
};
const schemaCommand = {
    name: 'schema',
    description: 'List configured MCP servers and tools with descriptions and schemas',
    kind: CommandKind.BUILT_IN,
    action: (context) => listAction(context, true, true),
};
const refreshCommand = {
    name: 'refresh',
    description: 'Restarts MCP servers',
    kind: CommandKind.BUILT_IN,
    action: async (context) => {
        const { config } = context.services;
        if (!config) {
            return {
                type: 'message',
                messageType: 'error',
                content: 'Config not loaded.',
            };
        }
        const toolRegistry = config.getToolRegistry();
        if (!toolRegistry) {
            return {
                type: 'message',
                messageType: 'error',
                content: 'Could not retrieve tool registry.',
            };
        }
        context.ui.addItem({
            type: 'info',
            text: 'Restarting MCP servers...',
        }, Date.now());
        await toolRegistry.restartMcpServers();
        // Update the client with the new tools
        const geminiClient = config.getGeminiClient();
        if (geminiClient) {
            await geminiClient.setTools();
        }
        // Reload the slash commands to reflect the changes.
        context.ui.reloadCommands();
        return listCommand.action(context, '');
    },
};
export const mcpCommand = {
    name: 'mcp',
    description: 'Manage configured Model Context Protocol (MCP) servers',
    kind: CommandKind.BUILT_IN,
    subCommands: [
        listCommand,
        descCommand,
        schemaCommand,
        authCommand,
        refreshCommand,
    ],
    action: async (context) => listAction(context),
};
//# sourceMappingURL=mcpCommand.js.map