import { normalizeToolArguments, resolveToolCallArgumentsForOllama } from './toolArguments';
export const extractToolCalls = (event, collector) => {
    const sources = [
        event.message?.tool_calls,
        event.tool_calls
    ];
    for (const source of sources) {
        if (!Array.isArray(source)) {
            continue;
        }
        for (const rawCall of source) {
            if (!rawCall || typeof rawCall !== 'object') {
                continue;
            }
            const name = typeof rawCall.function?.name === 'string' && rawCall.function?.name.length > 0
                ? rawCall.function.name
                : typeof rawCall.name === 'string' && rawCall.name.length > 0
                    ? rawCall.name
                    : 'unknown_tool';
            const candidateArguments = rawCall.function?.arguments ?? rawCall.arguments;
            const normalizedArguments = normalizeToolArguments(candidateArguments);
            const argumentText = normalizedArguments.text;
            const callId = typeof rawCall.id === 'string' && rawCall.id.length > 0
                ? rawCall.id
                : `${name}-${collector.size + 1}`;
            const existing = collector.get(callId);
            if (existing) {
                if (argumentText.length > 0) {
                    existing.arguments = argumentText;
                    existing.parsedArguments = normalizedArguments.value ?? existing.parsedArguments;
                }
                continue;
            }
            collector.set(callId, {
                callId,
                toolName: name,
                arguments: argumentText,
                parsedArguments: normalizedArguments.value
            });
        }
    }
};
export const handleStreamEvent = async (event, state, callbacks, toolCollector) => {
    state.rawEvents.push(event);
    if (event?.message?.content || event?.response || event?.done || event?.tool_calls) {
        console.debug('[Ollama] stream event received', {
            contentLength: event.message?.content?.length,
            hasResponse: typeof event.response === 'string',
            toolCallCount: Array.isArray(event.tool_calls) ? event.tool_calls.length : 0,
            done: event.done
        });
    }
    if (event.error) {
        const errorDetail = typeof event.error === 'string'
            ? event.error
            : (event.error.message ?? JSON.stringify(event.error));
        throw new Error(`Ollama error: ${errorDetail}`);
    }
    let emittedText = false;
    const responseText = event.response;
    if (typeof responseText === 'string' && responseText.length > 0) {
        const previousOutput = state.finalOutput;
        let delta = responseText;
        if (previousOutput.length > 0) {
            if (responseText.startsWith(previousOutput)) {
                delta = responseText.slice(previousOutput.length);
                state.finalOutput = responseText;
            }
            else if (previousOutput.startsWith(responseText)) {
                delta = '';
                state.finalOutput = previousOutput;
            }
            else {
                state.finalOutput = `${previousOutput}${responseText}`;
            }
        }
        else {
            state.finalOutput = responseText;
        }
        if (delta.length === 0 && state.finalOutput.length > previousOutput.length) {
            delta = state.finalOutput.slice(previousOutput.length);
        }
        if (delta.length > 0) {
            emittedText = true;
            if (callbacks.onOutputTextDelta) {
                await callbacks.onOutputTextDelta(delta);
            }
        }
    }
    const delta = event.message?.content;
    if (typeof delta === 'string' && delta.length > 0 && !emittedText) {
        state.finalOutput += delta;
        if (callbacks.onOutputTextDelta) {
            await callbacks.onOutputTextDelta(delta);
        }
        emittedText = true;
    }
    extractToolCalls(event, toolCollector);
    if (event.done) {
        const resolvedFinal = typeof event.response === 'string' && event.response.length > 0
            ? event.response
            : state.finalOutput;
        state.finalOutput = resolvedFinal;
        if (!state.messageCreated && callbacks.onMessageOutputCreated) {
            await callbacks.onMessageOutputCreated(resolvedFinal);
            state.messageCreated = true;
        }
        state.streamFinished = true;
    }
};
export const processBufferedLines = async (buffer, state, callbacks, toolCollector) => {
    let remaining = buffer;
    while (true) {
        const newlineIndex = remaining.indexOf('\n');
        if (newlineIndex === -1) {
            break;
        }
        const line = remaining.slice(0, newlineIndex).trim();
        remaining = remaining.slice(newlineIndex + 1);
        if (line.length === 0) {
            continue;
        }
        console.debug('[Ollama] processing stream line', { snippet: line.slice(0, 100), length: line.length });
        let parsed = null;
        try {
            parsed = JSON.parse(line);
        }
        catch (error) {
            console.warn('Failed to parse Ollama stream line', { line, error });
            continue;
        }
        await handleStreamEvent(parsed, state, callbacks, toolCollector);
        if (state.streamFinished) {
            break;
        }
    }
    return remaining;
};
export const resolveToolCallPayload = resolveToolCallArgumentsForOllama;
