import { resolveToolCallArgumentsForOllama } from './toolArguments';
const stringifyToolResult = (result) => {
    if (!result) {
        return '';
    }
    if (typeof result === 'string') {
        return result;
    }
    if (Array.isArray(result)) {
        const textSegments = result
            .map((item) => {
            if (!item || typeof item !== 'object') {
                return '';
            }
            if ('text' in item && typeof item.text === 'string') {
                return item.text ?? '';
            }
            if ('data' in item && typeof item.data === 'string') {
                return item.data ?? '';
            }
            return '';
        })
            .filter((segment) => segment.length > 0);
        if (textSegments.length > 0) {
            return textSegments.join('\n');
        }
    }
    if (typeof result === 'object' && 'content' in result) {
        const content = result.content;
        if (Array.isArray(content)) {
            const textSegments = content
                .map((item) => {
                if (!item || typeof item !== 'object') {
                    return '';
                }
                if ('text' in item && typeof item.text === 'string') {
                    return item.text ?? '';
                }
                return '';
            })
                .filter((segment) => segment.length > 0);
            if (textSegments.length > 0) {
                return textSegments.join('\n');
            }
        }
    }
    try {
        return JSON.stringify(result);
    }
    catch (error) {
        console.warn('Failed to stringify MCP tool result', error);
        return String(result);
    }
};
export const executeToolCall = async (call, tool, callbacks) => {
    console.log(`Executing tool call "${tool.originalName}" on MCP server "${tool.serverId}"`, call);
    const callId = call.callId;
    const argsString = call.arguments ?? '';
    const timestamp = Date.now();
    await callbacks.onToolCall?.(tool.originalName, argsString, {
        callId,
        status: 'in_progress',
        timestamp
    });
    let parsedArgs = undefined;
    if (argsString.length > 0) {
        try {
            parsedArgs = JSON.parse(argsString);
        }
        catch (error) {
            console.warn(`Failed to parse arguments for tool "${tool.originalName}"`, error);
            parsedArgs = argsString;
        }
    }
    let result;
    try {
        let callArguments;
        if (parsedArgs && typeof parsedArgs === 'object') {
            callArguments = parsedArgs;
        }
        else if (parsedArgs !== undefined) {
            callArguments = { value: parsedArgs };
        }
        const callOutcome = await tool.client.callTool(tool.originalName, callArguments ?? {});
        result = callOutcome?.result;
    }
    catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        const failureTimestamp = Date.now();
        await callbacks.onToolCall?.(tool.originalName, argsString, {
            callId,
            status: 'failed',
            error: errorMessage,
            timestamp: failureTimestamp
        });
        await callbacks.onToolOutput?.(tool.originalName, errorMessage, {
            callId,
            status: 'failed',
            error: errorMessage,
            timestamp: failureTimestamp
        });
        throw error;
    }
    const output = stringifyToolResult(result);
    const completionTimestamp = Date.now();
    await callbacks.onToolOutput?.(tool.originalName, output, {
        callId,
        status: 'completed',
        timestamp: completionTimestamp
    });
    return { output, metadata: { callId } };
};
export const runAttachmentToolCall = async (call, tool, callbacks) => {
    const callId = call.callId;
    const argsString = call.arguments ?? '';
    const startTimestamp = Date.now();
    await callbacks.onToolCall?.(tool.originalName, argsString, {
        callId,
        status: 'in_progress',
        timestamp: startTimestamp
    });
    let parsedArgs;
    if (argsString.length > 0) {
        try {
            const candidate = JSON.parse(argsString);
            if (candidate && typeof candidate === 'object' && !Array.isArray(candidate)) {
                parsedArgs = candidate;
            }
        }
        catch (error) {
            console.warn(`Failed to parse arguments for attachment tool "${tool.originalName}"`, {
                callId,
                error
            });
        }
    }
    try {
        const result = await tool.execute(parsedArgs);
        const output = JSON.stringify(result);
        const completionTimestamp = Date.now();
        await callbacks.onToolOutput?.(tool.originalName, output, {
            callId,
            status: 'completed',
            timestamp: completionTimestamp
        });
        return { output, metadata: { callId } };
    }
    catch (error) {
        const message = error instanceof Error ? error.message : String(error);
        const failureTimestamp = Date.now();
        await callbacks.onToolCall?.(tool.originalName, argsString, {
            callId,
            status: 'failed',
            error: message,
            timestamp: failureTimestamp
        });
        await callbacks.onToolOutput?.(tool.originalName, message, {
            callId,
            status: 'failed',
            error: message,
            timestamp: failureTimestamp
        });
        throw error;
    }
};
export const applyRejectedToolCalls = async (conversation, rejected, callbacks) => {
    for (const entry of rejected) {
        const reason = entry.reason ?? 'User rejected the tool call.';
        const timestamp = Date.now();
        const serialized = JSON.stringify({ error: reason });
        await callbacks.onToolCall?.(entry.toolDisplayName, entry.arguments, {
            callId: entry.callId,
            status: 'failed',
            error: reason,
            timestamp
        });
        await callbacks.onToolOutput?.(entry.toolDisplayName, reason, {
            callId: entry.callId,
            status: 'failed',
            error: reason,
            timestamp
        });
        conversation.push({
            role: 'tool',
            content: serialized,
            name: entry.toolUniqueName,
            tool_call_id: entry.callId
        });
    }
};
export const applyApprovedToolCalls = async (conversation, approved, toolContext, callbacks) => {
    for (const entry of approved) {
        const tool = toolContext.toolsByName.get(entry.toolUniqueName);
        if (!tool) {
            console.warn(`Approved tool call references unknown tool "${entry.toolUniqueName}"`);
            continue;
        }
        const call = {
            callId: entry.callId,
            toolName: entry.toolUniqueName,
            arguments: entry.arguments
        };
        if (tool.kind === 'attachment') {
            const { output } = await runAttachmentToolCall(call, tool, callbacks);
            conversation.push({
                role: 'tool',
                content: output,
                name: tool.uniqueName,
                tool_call_id: entry.callId
            });
            continue;
        }
        const { output } = await executeToolCall(call, tool, callbacks);
        conversation.push({
            role: 'tool',
            content: output,
            name: tool.uniqueName,
            tool_call_id: entry.callId
        });
    }
};
export const buildAssistantToolMessage = (finalOutput, toolCalls) => ({
    role: 'assistant',
    content: finalOutput,
    tool_calls: toolCalls.map((call) => ({
        id: call.callId,
        type: 'function',
        function: {
            name: call.toolName,
            arguments: resolveToolCallArgumentsForOllama(call)
        }
    }))
});
