/**
 * ChunkMessageMerger
 *
 * A utility for handling streaming message chunks and merging them into complete messages.
 */
/**
 * Creates a simple message merger for handling streaming message chunks
 * @returns An object with methods to push chunks and retrieve merged messages
 */
export function createSimpleMessageMerger() {
    let messages = [];
    const messageMap = new Map();
    // Tool call builder: messageId -> index -> build state
    const toolBuilders = new Map();
    /**
     * Normalizes role string to standard role
     * @param type - Role string from the input
     * @returns Normalized role
     */
    function normalizeRole(type) {
        switch (type) {
            case "ai":
                return "ai";
            case "human":
            case "user":
                return "human";
            case "system":
                return "system";
            case "tool":
                return "tool";
            case "developer":
                return "developer";
            default:
                return "ai";
        }
    }
    /**
     * Safely parses JSON string
     * @param str - JSON string to parse
     * @returns Parsed object or original string if parsing fails
     */
    function safeJsonParse(str) {
        try {
            return JSON.parse(str);
        }
        catch {
            return str; // Return original string if parsing fails
        }
    }
    /**
     * Ensures a message exists, creating it if needed
     * @param id - Message ID
     * @param role - Message role
     * @returns The message object
     */
    function ensureMessage(id, role) {
        const index = messageMap.get(id);
        if (index !== undefined) {
            return messages[index];
        }
        // Create new message
        let newMessage;
        switch (role) {
            case "human":
                newMessage = { id, role: "human", content: "" };
                break;
            case "system":
                newMessage = { id, role: "system", content: "" };
                break;
            case "tool":
                newMessage = { id, role: "tool", content: "", tool_call_id: "" };
                break;
            case "developer":
                newMessage = { id, role: "developer", content: "" };
                break;
            default:
                newMessage = { id, role: "ai", content: "" };
        }
        messages.push(newMessage);
        messageMap.set(id, messages.length - 1);
        return newMessage;
    }
    /**
     * Updates tool calls for a message
     * @param message - Message to update
     */
    function updateToolCalls(message) {
        if (message.role !== "ai")
            return;
        const builders = toolBuilders.get(message.id);
        if (!builders || builders.size === 0)
            return;
        const toolCalls = [];
        for (const [index, builder] of Array.from(builders.entries())) {
            if (builder.name && builder.id) {
                // Try to parse arguments as JSON object
                const args = builder.args.trim();
                const parsedArgs = safeJsonParse(args);
                // Create ToolCall object
                toolCalls.push({
                    id: builder.id,
                    name: builder.name,
                    args: typeof parsedArgs === "object" ? parsedArgs : { value: parsedArgs },
                    type: "tool_call",
                });
            }
        }
        // Only set tool_calls if there are any
        if (toolCalls.length > 0) {
            message.tool_calls = toolCalls;
        }
    }
    /**
     * Initialize messages
     * @param msgs - Initial messages
     */
    function initialMessages(msgs) {
        // Just store the messages as-is
        messages = msgs;
    }
    /**
     * Processes a message chunk
     * @param chunk - Message chunk to process
     */
    function push(chunk) {
        const role = normalizeRole(chunk.type);
        const message = ensureMessage(chunk.data.id, role);
        // Accumulate content
        if (chunk.data.content) {
            message.content = (message.content || "") + chunk.data.content;
        }
        // Handle tool call ID (for tool messages)
        if (message.role === "tool" && chunk.data.tool_call_id) {
            message.tool_call_id = chunk.data.tool_call_id;
        }
        // Handle tool call chunks (incremental)
        if (chunk.data.tool_call_chunks && message.role === "ai") {
            let builders = toolBuilders.get(message.id);
            if (!builders) {
                builders = new Map();
                toolBuilders.set(message.id, builders);
            }
            for (const chunk_item of chunk.data.tool_call_chunks) {
                let builder = builders.get(chunk_item.index);
                if (!builder) {
                    builder = { args: "" };
                    builders.set(chunk_item.index, builder);
                }
                if (chunk_item.name)
                    builder.name = chunk_item.name;
                if (chunk_item.id)
                    builder.id = chunk_item.id;
                if (chunk_item.args)
                    builder.args += chunk_item.args;
            }
            updateToolCalls(message);
        }
        // Handle complete tool calls (overwrite)
        if (chunk.data.tool_calls && message.role === "ai") {
            const toolCalls = chunk.data.tool_calls
                .filter((tc) => tc.name && tc.id)
                .map((tc) => ({
                id: tc.id,
                name: tc.name,
                args: tc.args,
                type: "tool_call",
                response: tc.response,
                status: "success",
            }));
            if (toolCalls.length > 0) {
                message.tool_calls = toolCalls;
            }
        }
        // Handle tool calls in additional_kwargs
        if (chunk.data.additional_kwargs?.tool_calls &&
            message.role === "ai" &&
            !message.tool_calls) {
            const toolCalls = [];
            for (const tc of chunk.data.additional_kwargs.tool_calls) {
                if (tc.function?.name && tc.id) {
                    // Convert to our format
                    const args = typeof tc.function.arguments === "string"
                        ? safeJsonParse(tc.function.arguments)
                        : tc.function.arguments || {};
                    toolCalls.push({
                        id: tc.id,
                        name: tc.function.name,
                        args,
                        type: "tool_call",
                    });
                }
            }
            if (toolCalls.length > 0) {
                message.tool_calls = toolCalls;
            }
        }
    }
    /**
     * Gets all messages with tool responses merged into tool calls
     * @returns Array of messages with tool responses merged into tool calls
     */
    function getMessages() {
        // Create a map to store tool responses by their tool_call_id
        const toolResponsesMap = {};
        // First pass: collect all tool responses
        messages.forEach((message) => {
            if (message.role === "tool" && message.tool_call_id) {
                toolResponsesMap[message.tool_call_id] = message;
            }
        });
        // Second pass: merge tool responses with their corresponding AI messages
        return messages
            .filter((message) => {
            // Keep all messages except tool messages
            return message.role !== "tool";
        })
            .map((message) => {
            if (message.role === "ai" && message.tool_calls) {
                // Create a new message object with merged tool responses
                const mergedMessage = { ...message };
                // Add tool responses to the corresponding tool calls
                if (mergedMessage.tool_calls) {
                    mergedMessage.tool_calls = mergedMessage.tool_calls.map((toolCall) => {
                        const toolResponse = toolResponsesMap[toolCall.id];
                        if (toolResponse) {
                            return {
                                ...toolCall,
                                response: toolResponse.content,
                                status: "success",
                            };
                        }
                        return toolCall;
                    });
                }
                return mergedMessage;
            }
            return message;
        });
    }
    /**
     * Gets messages without tool calls
     * @returns Array of messages without tool calls
     */
    function getMessagesWithoutToolCalls() {
        return messages.filter((message) => message.role !== "tool" &&
            (message.role !== "ai" || !message.tool_calls));
    }
    /**
     * Resets the message merger state
     */
    function reset() {
        messages = [];
        messageMap.clear();
        toolBuilders.clear();
    }
    return {
        push,
        initialMessages,
        getMessages,
        getMessagesWithoutToolCalls,
        reset,
    };
}
//# sourceMappingURL=ChunkMessageMerger.js.map