import { callMcpTool, listMcpTools, } from "./McpToolCatalog.js";
import McpProtocolError from "./McpProtocolError.js";
import { isMcpJsonObject, } from "./McpJsonValue.js";
export { listMcpTools, } from "./McpToolCatalog.js";
const METHOD_HANDLERS = new Map([
    ['initialize', handleInitialize],
    ['tools/list', handleToolsList],
    ['tools/call', handleToolsCall],
    ['resources/list', handleResourcesList],
    ['ping', handlePing],
]);
export function mcpParseError() {
    return errorResponse(null, new McpProtocolError(-32700, 'Parse error'));
}
export async function handleMcpMessage(graph, message, options) {
    const request = readRequest(message);
    if (request === null) {
        return errorResponse(null, new McpProtocolError(-32600, 'Invalid Request'));
    }
    if (request.id === undefined) {
        return null;
    }
    try {
        const result = await dispatchRequest(graph, request, options);
        return resultResponse(request.id, result);
    }
    catch (error) {
        return errorResponse(request.id, normalizeError(error));
    }
}
async function dispatchRequest(graph, request, options) {
    const handler = METHOD_HANDLERS.get(request.method);
    if (handler !== undefined) {
        return await handler(graph, request, options);
    }
    throw new McpProtocolError(-32601, `Method not found: ${request.method}`);
}
function handleInitialize(_graph, request, options) {
    return Promise.resolve({
        protocolVersion: readProtocolVersion(request.params) ?? '2025-06-18',
        capabilities: { tools: {} },
        serverInfo: {
            name: 'git-warp',
            version: options.serverVersion,
        },
    });
}
function handleToolsList() {
    return Promise.resolve({ tools: listMcpTools() });
}
async function handleToolsCall(graph, request) {
    const input = readToolCallInput(request.params);
    return await callMcpTool(graph, input.name, input.arguments);
}
function handleResourcesList() {
    return Promise.resolve({ resources: [] });
}
function handlePing() {
    return Promise.resolve({});
}
function readProtocolVersion(params) {
    const value = params?.['protocolVersion'];
    return typeof value === 'string' && value.length > 0 ? value : null;
}
function readToolCallInput(params) {
    return {
        name: readToolName(params),
        arguments: readToolArguments(params),
    };
}
function readToolName(params) {
    const name = params?.['name'];
    if (typeof name === 'string' && name.length > 0) {
        return name;
    }
    throw new McpProtocolError(-32602, 'tools/call requires a tool name');
}
function readToolArguments(params) {
    const args = params?.['arguments'];
    if (args === undefined) {
        return {};
    }
    if (isMcpJsonObject(args)) {
        return args;
    }
    throw new McpProtocolError(-32602, 'tools/call arguments must be an object');
}
function readRequest(value) {
    if (!isMcpJsonObject(value)) {
        return null;
    }
    if (!hasValidRequestHeader(value) || !hasValidRequestId(value) || !hasValidParams(value)) {
        return null;
    }
    return value;
}
function hasValidRequestHeader(value) {
    return value['jsonrpc'] === '2.0' && typeof value['method'] === 'string';
}
function hasValidRequestId(value) {
    return isRequestId(value['id']);
}
function hasValidParams(value) {
    return value['params'] === undefined || isMcpJsonObject(value['params']);
}
function isRequestId(value) {
    return (value === undefined
        || value === null
        || typeof value === 'string'
        || (typeof value === 'number' && Number.isFinite(value)));
}
function resultResponse(id, result) {
    return { jsonrpc: '2.0', id, result };
}
function errorResponse(id, error) {
    return {
        jsonrpc: '2.0',
        id,
        error: {
            code: error.code,
            message: error.message,
            ...(error.data !== undefined ? { data: error.data } : {}),
        },
    };
}
function normalizeError(error) {
    if (error instanceof McpProtocolError) {
        return error;
    }
    const message = error instanceof Error ? error.message : 'Internal MCP error';
    return new McpProtocolError(-32000, message);
}
