import { isServerRuntime } from '../utils/api.js';
/**
 * cancel.ts — Cancel an in-flight V3 agent run, or cancel all active runs.
 *
 * Usage:
 *   vig cancel <context_id>       Cancel a single run
 *   vig cancel --all              Cancel every currently-active run
 *   vig cancel --list             Just list active runs (no cancellation)
 */
import chalk from 'chalk';
import { createSpinner, CH } from '../utils/logger.js';
export class CancelCommand {
    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);
    }
    async listActive(baseUrl) {
        const resp = await fetch(`${baseUrl}/api/runs/active`, { headers: this.getHeaders() });
        if (!resp.ok) {
            if (resp.status === 404 || resp.status === 502 || resp.status === 503) {
                this.logger.error(`V3 cancel API is not available on ${baseUrl}. Backend may not expose /api/runs/active. ` +
                    `(Requires V3 agent server.py with the cancel endpoint patched in.)`);
            }
            else if (resp.status === 401 || resp.status === 403) {
                this.logger.error(`Authentication failed (${resp.status}). Run \`vig login\` first.`);
            }
            else {
                this.logger.error(`Failed to list active runs: ${resp.status} ${resp.statusText}`);
            }
            return null;
        }
        return (await resp.json());
    }
    async cancelOne(baseUrl, contextId) {
        const resp = await fetch(`${baseUrl}/api/runs/${encodeURIComponent(contextId)}/cancel`, { method: 'POST', headers: this.getHeaders() });
        if (!resp.ok) {
            if (resp.status === 404) {
                this.logger.warn(`No active run for context_id=${contextId}`);
            }
            else if (resp.status === 401 || resp.status === 403) {
                this.logger.error(`Authentication failed (${resp.status}). Run \`vig login\` first.`);
            }
            else {
                this.logger.error(`Cancel failed for ${contextId}: ${resp.status} ${resp.statusText}`);
            }
            return null;
        }
        return (await resp.json());
    }
    async run(contextId, options) {
        const baseUrl = this.getBaseUrl();
        if (options.list) {
            const spinner = createSpinner('Loading active runs...').start();
            const active = await this.listActive(baseUrl);
            spinner.stop();
            if (!active)
                return;
            if (options.json) {
                console.log(JSON.stringify(active, null, 2));
                return;
            }
            if (active.active_count === 0) {
                this.logger.info(chalk.dim('No active runs.'));
                return;
            }
            console.log(chalk.bold(`\n${CH.success} Active Runs (${active.active_count}/${active.max_concurrent_runs})\n`));
            for (const cid of active.active_context_ids) {
                console.log(`  ${chalk.cyan(cid)}`);
            }
            console.log();
            return;
        }
        if (options.all) {
            const spinner = createSpinner('Loading active runs...').start();
            const active = await this.listActive(baseUrl);
            spinner.stop();
            if (!active)
                return;
            if (active.active_count === 0) {
                this.logger.info(chalk.dim('No active runs to cancel.'));
                return;
            }
            const results = [];
            for (const cid of active.active_context_ids) {
                const sp = createSpinner(`Cancelling ${cid}...`).start();
                const r = await this.cancelOne(baseUrl, cid);
                sp.stop();
                if (r) {
                    results.push(r);
                    this.logger.success(`Cancelled ${chalk.cyan(cid)} (asyncio_cancelled=${r.asyncio_cancelled})`);
                }
            }
            if (options.json)
                console.log(JSON.stringify({ cancelled: results }, null, 2));
            return;
        }
        if (!contextId) {
            this.logger.error('Usage: vig cancel <context_id> | --all | --list');
            return;
        }
        const spinner = createSpinner(`Cancelling ${contextId}...`).start();
        const r = await this.cancelOne(baseUrl, contextId);
        spinner.stop();
        if (!r)
            return;
        if (options.json) {
            console.log(JSON.stringify(r, null, 2));
            return;
        }
        this.logger.success(`Cancelled ${chalk.cyan(contextId)} ` +
            `(asyncio_cancelled=${r.asyncio_cancelled}, active_runs_after=${r.active_runs_after})`);
    }
}
