"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.dispatchBuiltinTool = dispatchBuiltinTool;
exports.listServerTools = listServerTools;
const logger_1 = require("../../../lib/logger");
const connection_lifecycle_1 = require("./connection-lifecycle");
/**
 * Dispatch a tool call directly to a built-in server's handler,
 * bypassing MCP Client/Transport entirely. Returns null if the server
 * or tool is not a built-in — caller should fall through to MCP transport.
 *
 * Each built-in server is lazily instantiated once and cached. Tool handlers
 * are called via server._registeredTools[toolName].handler(args). This
 * eliminates the InMemoryTransport bottleneck under concurrent load.
 */
async function dispatchBuiltinTool(serverId, toolName, args) {
    const builtinFactories = (0, connection_lifecycle_1.getBuiltinFactories)();
    const builtinServers = (0, connection_lifecycle_1.getBuiltinServers)();
    // Normalize and match against builtin factories
    const norm = (s) => s.replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
    const normId = norm(serverId);
    let matchedName = null;
    for (const [name] of builtinFactories) {
        const normName = norm(name);
        if (normName === normId || normName.includes(normId) || normId.includes(normName)) {
            matchedName = name;
            break;
        }
    }
    if (!matchedName)
        return null;
    // Lazily create and cache the server instance
    if (!builtinServers.has(matchedName)) {
        const factory = builtinFactories.get(matchedName);
        const server = await factory();
        builtinServers.set(matchedName, server);
        logger_1.loggerRegistry.info(`[lt-mcp:builtin] ${matchedName} ready (direct dispatch)`);
    }
    const server = builtinServers.get(matchedName);
    const tool = server._registeredTools?.[toolName];
    if (!tool?.handler)
        return null;
    // Call the handler directly — no transport, no JSON-RPC.
    // Tool handlers return MCP-shaped responses: { content: [{ type: 'text', text: '...' }] }
    // Parse the text content the same way callServerTool does.
    const mcpResponse = await tool.handler(args);
    let parsed = mcpResponse;
    if (mcpResponse && Array.isArray(mcpResponse.content)) {
        const textContent = mcpResponse.content.find((c) => c.type === 'text');
        if (textContent && 'text' in textContent) {
            try {
                parsed = JSON.parse(textContent.text);
            }
            catch {
                parsed = mcpResponse.isError ? { error: textContent.text } : textContent.text;
            }
        }
    }
    const isError = parsed && typeof parsed === 'object' && 'error' in parsed;
    logger_1.loggerRegistry.debug(`[lt-mcp:builtin] ${matchedName}/${toolName} ok=${!isError} resultKeys=[${typeof parsed === 'object' && parsed ? Object.keys(parsed).join(',') : 'raw'}]`);
    return { dispatched: true, result: parsed };
}
/**
 * List tools from a connected server.
 */
async function listServerTools(serverId) {
    const clients = (0, connection_lifecycle_1.getClients)();
    const client = clients.get(serverId);
    if (!client) {
        throw new Error(`MCP server ${serverId} is not connected`);
    }
    const { tools } = await client.listTools();
    return tools.map((t) => ({
        name: t.name,
        description: t.description || '',
        inputSchema: t.inputSchema || {},
    }));
}
