/**
 * Codex stream event handling.
 *
 * Converts Codex SDK events into the unified StreamCallback format
 * used throughout the takt codebase.
 */
export function createStreamTrackingState() {
    return {
        startedItems: new Set(),
        outputOffsets: new Map(),
        textOffsets: new Map(),
        thinkingOffsets: new Map(),
        anonymousItemIds: new Map(),
    };
}
// ---- Stream emission helpers ----
export function extractThreadId(value) {
    if (!value || typeof value !== 'object')
        return undefined;
    const record = value;
    const id = record.id ?? record.thread_id ?? record.threadId;
    return typeof id === 'string' ? id : undefined;
}
export function emitInit(onStream, model, sessionId) {
    if (!onStream)
        return;
    onStream({
        type: 'init',
        data: {
            model: model || 'codex',
            sessionId: sessionId || 'unknown',
        },
    });
}
export function emitText(onStream, text) {
    if (!onStream || !text)
        return;
    onStream({ type: 'text', data: { text } });
}
export function emitThinking(onStream, thinking) {
    if (!onStream || !thinking)
        return;
    onStream({ type: 'thinking', data: { thinking } });
}
export function emitToolUse(onStream, tool, input, id) {
    if (!onStream)
        return;
    onStream({ type: 'tool_use', data: { tool, input, id } });
}
function recordToolUse(state, tool, input, id) {
    state.activeTool = { tool, input, id };
}
function clearActiveTool(state, id) {
    if (state.activeTool?.id === id) {
        state.activeTool = undefined;
    }
}
function resolveCodexItemId(item, state) {
    if (item.id) {
        return item.id;
    }
    const existingId = state.anonymousItemIds.get(item.type);
    if (existingId) {
        return existingId;
    }
    const id = `item_${Math.random().toString(36).slice(2, 10)}`;
    state.anonymousItemIds.set(item.type, id);
    return id;
}
function releaseAnonymousItemId(item, state, id) {
    if (item.id) {
        return;
    }
    if (state.anonymousItemIds.get(item.type) === id) {
        state.anonymousItemIds.delete(item.type);
    }
}
export function emitToolResult(onStream, content, isError) {
    if (!onStream)
        return;
    onStream({ type: 'tool_result', data: { content, isError } });
}
export function emitToolOutput(onStream, tool, output) {
    if (!onStream || !output)
        return;
    onStream({ type: 'tool_output', data: { tool, output } });
}
export function emitResult(onStream, success, result, sessionId, failureCategory) {
    if (!onStream)
        return;
    onStream({
        type: 'result',
        data: {
            result,
            sessionId: sessionId || 'unknown',
            success,
            error: success ? undefined : result || undefined,
            ...(failureCategory ? { failureCategory } : {}),
        },
    });
}
export function formatFileChangeSummary(changes) {
    if (!changes.length)
        return '';
    return changes
        .map((change) => {
        const kind = change.kind ? `${change.kind}: ` : '';
        return `${kind}${change.path ?? ''}`.trim();
    })
        .filter(Boolean)
        .join('\n');
}
export function emitCodexItemStart(item, onStream, state) {
    emitCodexItemStartWithId(item, onStream, state, resolveCodexItemId(item, state));
}
function emitCodexItemStartWithId(item, onStream, state, id) {
    if (state.startedItems.has(id))
        return;
    switch (item.type) {
        case 'command_execution': {
            const command = typeof item.command === 'string' ? item.command : '';
            recordToolUse(state, 'Bash', { command }, id);
            emitToolUse(onStream, 'Bash', { command }, id);
            state.startedItems.add(id);
            break;
        }
        case 'mcp_tool_call': {
            const tool = typeof item.tool === 'string' ? item.tool : 'Tool';
            const args = (item.arguments ?? {});
            recordToolUse(state, tool, args, id);
            emitToolUse(onStream, tool, args, id);
            state.startedItems.add(id);
            break;
        }
        case 'web_search': {
            const query = typeof item.query === 'string' ? item.query : '';
            recordToolUse(state, 'WebSearch', { query }, id);
            emitToolUse(onStream, 'WebSearch', { query }, id);
            state.startedItems.add(id);
            break;
        }
        case 'file_change': {
            const changes = Array.isArray(item.changes) ? item.changes : [];
            const summary = formatFileChangeSummary(changes);
            recordToolUse(state, 'Edit', { file_path: summary || 'patch' }, id);
            emitToolUse(onStream, 'Edit', { file_path: summary || 'patch' }, id);
            state.startedItems.add(id);
            break;
        }
        default:
            break;
    }
}
export function emitCodexItemCompleted(item, onStream, state) {
    const id = resolveCodexItemId(item, state);
    switch (item.type) {
        case 'reasoning': {
            const text = typeof item.text === 'string' ? item.text : '';
            if (text) {
                const prev = state.thinkingOffsets.get(id) ?? 0;
                if (text.length > prev) {
                    emitThinking(onStream, text.slice(prev) + '\n');
                    state.thinkingOffsets.set(id, text.length);
                }
            }
            break;
        }
        case 'agent_message': {
            const text = typeof item.text === 'string' ? item.text : '';
            if (text) {
                const prev = state.textOffsets.get(id) ?? 0;
                if (text.length > prev) {
                    emitText(onStream, text.slice(prev));
                    state.textOffsets.set(id, text.length);
                }
            }
            break;
        }
        case 'command_execution': {
            if (!state.startedItems.has(id)) {
                emitCodexItemStartWithId(item, onStream, state, id);
            }
            const output = typeof item.aggregated_output === 'string' ? item.aggregated_output : '';
            if (output) {
                const prev = state.outputOffsets.get(id) ?? 0;
                if (output.length > prev) {
                    emitToolOutput(onStream, 'Bash', output.slice(prev));
                    state.outputOffsets.set(id, output.length);
                }
            }
            const exitCode = typeof item.exit_code === 'number' ? item.exit_code : undefined;
            const status = typeof item.status === 'string' ? item.status : '';
            const isError = status === 'failed' || (exitCode !== undefined && exitCode !== 0);
            const content = output || (exitCode !== undefined ? `Exit code: ${exitCode}` : '');
            emitToolResult(onStream, content, isError);
            clearActiveTool(state, id);
            break;
        }
        case 'mcp_tool_call': {
            if (!state.startedItems.has(id)) {
                emitCodexItemStartWithId(item, onStream, state, id);
            }
            const status = typeof item.status === 'string' ? item.status : '';
            const isError = status === 'failed' || !!item.error;
            const errorMessage = item.error && typeof item.error === 'object' && 'message' in item.error
                ? String(item.error.message ?? '')
                : '';
            let content = errorMessage;
            if (!content && item.result && typeof item.result === 'object') {
                try {
                    content = JSON.stringify(item.result);
                }
                catch {
                    content = '';
                }
            }
            emitToolResult(onStream, content, isError);
            clearActiveTool(state, id);
            break;
        }
        case 'web_search': {
            if (!state.startedItems.has(id)) {
                emitCodexItemStartWithId(item, onStream, state, id);
            }
            emitToolResult(onStream, 'Search completed', false);
            clearActiveTool(state, id);
            break;
        }
        case 'file_change': {
            if (!state.startedItems.has(id)) {
                emitCodexItemStartWithId(item, onStream, state, id);
            }
            const status = typeof item.status === 'string' ? item.status : '';
            const isError = status === 'failed';
            const changes = Array.isArray(item.changes) ? item.changes : [];
            const summary = formatFileChangeSummary(changes);
            emitToolResult(onStream, summary || 'Applied patch', isError);
            clearActiveTool(state, id);
            break;
        }
        default:
            break;
    }
    releaseAnonymousItemId(item, state, id);
}
export function emitCodexItemUpdate(item, onStream, state) {
    const id = resolveCodexItemId(item, state);
    switch (item.type) {
        case 'command_execution': {
            if (!state.startedItems.has(id)) {
                emitCodexItemStartWithId(item, onStream, state, id);
            }
            const output = typeof item.aggregated_output === 'string' ? item.aggregated_output : '';
            if (output) {
                const prev = state.outputOffsets.get(id) ?? 0;
                if (output.length > prev) {
                    emitToolOutput(onStream, 'Bash', output.slice(prev));
                    state.outputOffsets.set(id, output.length);
                }
            }
            break;
        }
        case 'agent_message': {
            const text = typeof item.text === 'string' ? item.text : '';
            if (text) {
                const prev = state.textOffsets.get(id) ?? 0;
                if (text.length > prev) {
                    emitText(onStream, text.slice(prev));
                    state.textOffsets.set(id, text.length);
                }
            }
            break;
        }
        case 'reasoning': {
            const text = typeof item.text === 'string' ? item.text : '';
            if (text) {
                const prev = state.thinkingOffsets.get(id) ?? 0;
                if (text.length > prev) {
                    emitThinking(onStream, text.slice(prev));
                    state.thinkingOffsets.set(id, text.length);
                }
            }
            break;
        }
        case 'file_change':
        case 'mcp_tool_call':
        case 'web_search': {
            if (!state.startedItems.has(id)) {
                emitCodexItemStartWithId(item, onStream, state, id);
            }
            break;
        }
        default:
            break;
    }
}
//# sourceMappingURL=CodexStreamHandler.js.map