/**
 * Print mode (single-shot): Send prompts, output result, exit.
 *
 * Used for:
 * - `pi -p "prompt"` - text output with tool call summaries and streamed text
 * - `pi --mode json "prompt"` - JSON event stream
 */
import chalk from 'chalk';
import { drainPendingRefreshes } from '../app/session/pending-refresh-runner.js';
/**
 * Format a tool call for display.
 * If the tool has a description arg, show "name: description".
 * Otherwise show each arg as indented colored key: value lines.
 */
function formatToolCall(toolName, args) {
    if (!args || typeof args !== 'object' || Object.keys(args).length === 0) {
        return chalk.cyan(toolName);
    }
    if (args.description) {
        return `${chalk.cyan(toolName)}: ${args.description}`;
    }
    const lines = Object.entries(args).map(([key, value]) => {
        const str = typeof value === 'string' ? value : JSON.stringify(value);
        return `        ${chalk.dim(key)}: ${str}`;
    });
    return `${chalk.cyan(toolName)}\n${lines.join('\n')}`;
}
/**
 * Run in print (single-shot) mode.
 * Sends prompts to the agent and outputs the result.
 */
export async function runPrintMode(session, options) {
    const { mode, messages = [], initialMessage, initialImages } = options;
    if (mode === 'json') {
        const header = session.sessionManager.getHeader();
        if (header) {
            console.log(JSON.stringify(header));
        }
    }
    if (options.fetchBalance) {
        const balance = await options.fetchBalance();
        if (balance && !balance.isUnlimited && balance.creditsRemaining <= 0) {
            const msg = balance.hasTeamBilling
                ? 'Your team is out of credits. Contact your billing admin.'
                : 'You are out of credits. Please upgrade your plan.';
            console.error(msg);
            process.exit(1);
        }
    }
    // Set up extensions for print mode (no UI)
    await session.bindExtensions({
        commandContextActions: {
            waitForIdle: () => session.agent.waitForIdle(),
            newSession: async (options) => {
                const success = await session.newSession({ parentSession: options?.parentSession });
                if (success && options?.setup) {
                    await options.setup(session.sessionManager);
                }
                return { cancelled: !success };
            },
            fork: async (entryId) => {
                const result = await session.fork(entryId);
                return { cancelled: result.cancelled };
            },
            navigateTree: async (targetId, options) => {
                const result = session.navigateTree(targetId, {
                    label: options?.label
                });
                return { cancelled: result.cancelled };
            },
            switchSession: async (sessionPath) => {
                const success = await session.switchSession(sessionPath);
                return { cancelled: !success };
            },
            reload: async () => {
                await session.reload();
            }
        },
        onError: (err) => {
            console.error(`Extension error (${err.extensionPath}): ${err.error}`);
        }
    });
    // Track whether we're mid-text-block (for newline management)
    let inTextBlock = false;
    // Always subscribe to enable session persistence via _handleAgentLoopEvent
    session.subscribe((event) => {
        if (mode === 'json') {
            console.log(JSON.stringify(event));
            return;
        }
        // Text mode: stream tool calls and text as they happen
        if (mode === 'text') {
            switch (event.type) {
                case 'tool_execution_start': {
                    if (inTextBlock) {
                        process.stdout.write('\n');
                        inTextBlock = false;
                    }
                    const line = formatToolCall(event.toolName, event.args);
                    console.error(chalk.dim('  ▶ ') + line);
                    break;
                }
                case 'message_end': {
                    // Print text from completed assistant message
                    if (event.message.role === 'assistant') {
                        const msg = event.message;
                        for (const content of msg.content) {
                            if (content.type === 'text' && content.text) {
                                process.stdout.write(content.text);
                                inTextBlock = true;
                            }
                        }
                    }
                    break;
                }
                case 'agent_end': {
                    if (inTextBlock) {
                        process.stdout.write('\n');
                        inTextBlock = false;
                    }
                    // Emit session ID to stdout so callers can read it
                    const sessionId = session.sessionManager.getSessionId();
                    if (sessionId) {
                        console.log(`[session:${sessionId}]`);
                    }
                    // Check for errors
                    const msgs = event.messages;
                    const last = msgs[msgs.length - 1];
                    if (last?.role === 'assistant') {
                        const msg = last;
                        if ((msg.stopReason === 'error' || msg.stopReason === 'aborted') &&
                            !session.isRetrying) {
                            console.error(msg.errorMessage || `Request ${msg.stopReason}`);
                            process.exit(1);
                        }
                    }
                    break;
                }
            }
        }
    });
    const continuePendingRefreshes = async () => {
        const result = await drainPendingRefreshes({
            consumePendingRefresh: () => session.consumePendingRefresh(),
            beforeRefresh: async () => {
                await session.newSession({ preserveAutonomous: true });
            },
            preparePendingRefresh: (refresh) => session.preparePendingRefresh(refresh),
            prompt: (prompt) => session.prompt(prompt),
            surface: 'print mode'
        });
        if (result.limitExceeded) {
            throw new Error(result.message);
        }
    };
    // Send initial message with attachments
    if (initialMessage) {
        await session.prompt(initialMessage, { images: initialImages });
        await continuePendingRefreshes();
    }
    // Send remaining messages
    for (const message of messages) {
        await session.prompt(message);
        await continuePendingRefreshes();
    }
    // Ensure stdout is fully flushed before returning
    // This prevents race conditions where the process exits before all output is written
    await new Promise((resolve, reject) => {
        process.stdout.write('', (err) => {
            if (err)
                reject(err);
            else
                resolve();
        });
    });
}
//# sourceMappingURL=print-mode.js.map