import { isServerRuntime } from '../utils/api.js';
/**
 * fork.ts — Fork from an existing V3 agent run and stream the result.
 */
import chalk from 'chalk';
import { createRequire } from 'node:module';
import { createSpinner, CH } from '../utils/logger.js';
const require = createRequire(import.meta.url);
export class ForkCommand {
    config;
    logger;
    constructor(config, logger) {
        this.config = config;
        this.logger = logger;
    }
    getHeaders() {
        const headers = { 'Content-Type': 'application/json' };
        const token = process.env.VIGTHORIA_TOKEN ||
            process.env.VIGTHORIA_AUTH_TOKEN ||
            this.config.get('authToken');
        if (token) {
            headers['Authorization'] = `Bearer ${token}`;
            headers['Cookie'] = `vigthoria-auth-token=${token}`;
        }
        const serviceKey = process.env.VIGTHORIA_V3_SERVICE_KEY;
        if (serviceKey)
            headers['X-Service-Key'] = serviceKey;
        return headers;
    }
    getBaseUrl() {
        const configuredApiUrl = String(this.config.get('apiUrl') || 'https://coder.vigthoria.io').replace(/\/$/, '');
        const allowLocal = isServerRuntime() && process.env.VIGTHORIA_ALLOW_LOCAL_V3_AGENT === '1';
        return (process.env.VIGTHORIA_V3_AGENT_URL ||
            process.env.V3_AGENT_URL ||
            (allowLocal ? 'http://127.0.0.1:8030' : null) ||
            configuredApiUrl);
    }
    resolveWorkspaceRoot(project) {
        if (/^[a-zA-Z]:[\\/]/.test(project) || /^\\\\/.test(project))
            return '';
        if (typeof require !== 'undefined') {
            try {
                const path = require('path');
                if (!path.isAbsolute(project))
                    return '';
            }
            catch { }
        }
        return project;
    }
    async run(runId, message, options) {
        const project = options.project || process.cwd();
        const workspace = this.resolveWorkspaceRoot(project);
        const eventIndex = options.eventIndex || 0;
        const spinner = createSpinner(`Forking run ${runId}...`).start();
        try {
            const baseUrl = this.getBaseUrl();
            const body = {
                workspace_root: workspace,
                from_event_index: eventIndex,
                new_request: message || '',
                stream: true,
                context: '',
            };
            const resp = await fetch(`${baseUrl}/api/runs/${encodeURIComponent(runId)}/fork`, {
                method: 'POST',
                headers: this.getHeaders(),
                body: JSON.stringify(body),
            });
            if (!resp.ok) {
                spinner.stop();
                if (resp.status === 404) {
                    this.logger.error(`Run ${runId} not found or has no event log.`);
                }
                else if (resp.status === 502 || resp.status === 503) {
                    this.logger.error(`V3 run-history route is not available on ${baseUrl}. Backend may not expose /api/runs.`);
                }
                else {
                    this.logger.error(`Fork failed: ${resp.status} ${resp.statusText}`);
                }
                return;
            }
            spinner.stop();
            console.log(chalk.bold(`\n${CH.success} Forked from ${chalk.cyan(runId)} at event ${eventIndex}\n`));
            if (!resp.body) {
                this.logger.error('No response body');
                return;
            }
            // Stream SSE events
            const reader = resp.body.getReader();
            const decoder = new TextDecoder();
            let buffer = '';
            let toolCallNum = 0;
            while (true) {
                const { done, value } = await reader.read();
                if (done)
                    break;
                buffer += decoder.decode(value, { stream: true });
                const lines = buffer.split('\n');
                buffer = lines.pop() || '';
                for (const line of lines) {
                    if (!line.startsWith('data: '))
                        continue;
                    const payload = line.slice(6).trim();
                    if (payload === '[DONE]') {
                        console.log(chalk.bold(`\n${CH.success} Fork run complete\n`));
                        return;
                    }
                    try {
                        const evt = JSON.parse(payload);
                        const type = evt.type || 'unknown';
                        if (options.json) {
                            console.log(JSON.stringify(evt));
                            continue;
                        }
                        switch (type) {
                            case 'context':
                                console.log(chalk.blue(`  context: ${evt.context_id || '?'}`) +
                                    (evt.forked_from ? chalk.dim(` (forked from ${evt.forked_from})`) : ''));
                                break;
                            case 'start':
                                console.log(chalk.green(`  ▶ START`) + ` task=${evt.task_id || '?'}` +
                                    (evt.forked_from ? chalk.dim(` forked_from=${evt.forked_from}`) : ''));
                                break;
                            case 'plan':
                                console.log(chalk.magenta(`  📋 PLAN`) + ` ${evt.tasks?.length || 0} tasks`);
                                break;
                            case 'tool_call':
                                toolCallNum++;
                                console.log(chalk.yellow(`  🔧 #${toolCallNum}`) + ` ${evt.name || '?'}(${JSON.stringify(evt.arguments || {}).substring(0, 60)})`);
                                break;
                            case 'tool_result': {
                                const icon = evt.success !== false ? chalk.green('✓') : chalk.red('✗');
                                console.log(`    ${icon} ${evt.name || '?'}: ${chalk.dim((evt.output || '').substring(0, 100))}`);
                                break;
                            }
                            case 'message':
                                console.log(chalk.cyan(`  💬 `) + (evt.content || '').substring(0, 150));
                                break;
                            case 'complete': {
                                const seal = evt.seal_score ? `[${evt.seal_score.tier} ${evt.seal_score.overall}]` : '';
                                console.log(chalk.green(`  ✅ COMPLETE `) + chalk.yellow(seal) +
                                    ` ${evt.iterations || '?'} iterations, ${evt.tool_calls || '?'} tool calls`);
                                break;
                            }
                            case 'error':
                                console.log(chalk.red(`  ❌ ERROR: `) + (evt.message || '').substring(0, 200));
                                break;
                            default:
                                console.log(chalk.dim(`  ${type}: ${JSON.stringify(evt).substring(0, 80)}`));
                        }
                    }
                    catch {
                        // skip unparseable lines
                    }
                }
            }
        }
        catch (err) {
            spinner.stop();
            this.logger.error(`Fork error: ${err.message}`);
        }
    }
}
