/**
 * Returns a setter that keeps reasoning events ordered while merging updates.
 */
export const createReasoningEventUpdater = (setStreamState) => (event) => {
    setStreamState((prev) => {
        const existing = prev.reasoningEvents ?? [];
        const nextEvents = existing.filter((entry) => entry.id !== event.id);
        nextEvents.push({ ...event });
        nextEvents.sort((a, b) => a.timestamp - b.timestamp);
        return {
            ...prev,
            reasoningEvents: nextEvents
        };
    });
};
/**
 * Returns a setter that updates message events in timestamp order.
 */
export const createMessageEventUpdater = (setStreamState) => (event) => {
    setStreamState((prev) => {
        const existing = prev.messageEvents ?? [];
        const nextEvents = existing.filter((entry) => entry.id !== event.id);
        nextEvents.push({ ...event });
        nextEvents.sort((a, b) => a.timestamp - b.timestamp);
        return {
            ...prev,
            messageEvents: nextEvents
        };
    });
};
/**
 * Manages streaming tool-call updates while keeping a snapshot in sync with React state.
 */
export const createToolCallManager = ({ initialLog = [], setStreamState, snapshotRef }) => {
    const toolCallLog = initialLog.map((entry) => ({ ...entry }));
    const updateSnapshot = () => {
        snapshotRef.current = toolCallLog.map((entry) => ({ ...entry }));
    };
    updateSnapshot();
    const sync = (callId, update) => {
        const timestamp = update.timestamp ?? Date.now();
        const normalizedStatus = update.status ?? 'in_progress';
        const normalizedArgs = update.args ?? '';
        const existingIndex = toolCallLog.findIndex((entry) => entry.id === callId);
        if (existingIndex === -1) {
            const entry = {
                id: callId,
                name: update.name,
                args: normalizedArgs,
                status: normalizedStatus,
                output: update.output,
                error: update.error,
                startedAt: timestamp,
                updatedAt: timestamp,
                completedAt: update.completedAt ?? (normalizedStatus.toLowerCase() === 'completed' ? timestamp : undefined)
            };
            toolCallLog.push(entry);
            const entryCopy = { ...entry };
            setStreamState((prev) => ({
                ...prev,
                toolCalls: [...prev.toolCalls, entryCopy]
            }));
            updateSnapshot();
            return entry;
        }
        const existing = toolCallLog[existingIndex];
        const nextStatus = normalizedStatus || existing.status;
        const nextArgs = update.args ?? existing.args;
        const completedAtCandidate = update.completedAt ??
            (nextStatus && nextStatus.toLowerCase() === 'completed' ? timestamp : existing.completedAt);
        const updated = {
            ...existing,
            name: update.name ?? existing.name,
            args: nextArgs,
            status: nextStatus,
            output: update.output ?? existing.output,
            error: update.error ?? existing.error,
            updatedAt: timestamp,
            completedAt: completedAtCandidate
        };
        toolCallLog[existingIndex] = updated;
        const updatedCopy = { ...updated };
        setStreamState((prev) => ({
            ...prev,
            toolCalls: prev.toolCalls.map((toolCall) => (toolCall.id === callId ? updatedCopy : toolCall))
        }));
        updateSnapshot();
        return updated;
    };
    const reset = (next = []) => {
        toolCallLog.length = 0;
        next.forEach((entry) => {
            toolCallLog.push({ ...entry });
        });
        updateSnapshot();
        setStreamState((prev) => ({
            ...prev,
            toolCalls: toolCallLog.map((entry) => ({ ...entry }))
        }));
    };
    const getSnapshot = () => toolCallLog.map((entry) => ({ ...entry }));
    return {
        sync,
        reset,
        getSnapshot
    };
};
