"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.prepareRun = prepareRun;
exports.execRun = execRun;
const fs_1 = require("fs");
const path_1 = require("path");
const core_1 = require("@vsaf/core");
const progress_js_1 = require("../ui/progress.js");
async function prepareRun(workflowName, projectPath, options) {
    const config = (0, core_1.loadConfig)(projectPath);
    const workflowPath = (0, path_1.join)(projectPath, '.vsaf', 'workflows', `${workflowName}.yaml`);
    if (!(0, fs_1.existsSync)(workflowPath)) {
        throw new Error(`Workflow not found: "${workflowName}" (expected at ${workflowPath})`);
    }
    const yamlContent = (0, fs_1.readFileSync)(workflowPath, 'utf-8');
    const graph = (0, core_1.parseWorkflow)(yamlContent);
    return { graph, config, args: options.args };
}
async function execRun(workflowName, projectPath, options) {
    const { graph, config, args } = await prepareRun(workflowName, projectPath, options);
    // Check for AI nodes — vsaf run only supports bash-only workflows
    const hasAINodes = [...graph.nodes.values()].some(n => n.type === 'prompt' || n.type === 'command');
    if (hasAINodes) {
        console.error('[vsaf] This workflow contains AI nodes. Use `/vsaf ' + workflowName + '` inside Claude instead.');
        process.exit(1);
    }
    console.log(`[vsaf] Loading config from .vsaf/config.yaml`);
    console.log(`[vsaf] Parsing workflow: ${workflowName}`);
    const wsManager = new core_1.WorkspaceManager({ exclude: config.isolation.exclude });
    const ws = await wsManager.create(projectPath, workflowName);
    console.log(`[vsaf] Creating workspace: ${ws.sourcePath}`);
    const storeDir = (0, path_1.join)(projectPath, '.vsaf', 'storage');
    const runStore = new core_1.RunStore(storeDir);
    const run = runStore.create(workflowName, args, ws.sourcePath, ws.artifactsPath, projectPath);
    console.log(`[vsaf] Starting DAG execution (${graph.nodes.size} nodes)\n`);
    const startTime = Date.now();
    const callbacks = {
        onNodeStart: (nodeId) => {
            console.log((0, progress_js_1.formatNodeStatus)(nodeId, 'running'));
            runStore.updateNode(run.runId, nodeId, { status: 'running', startedAt: new Date().toISOString() });
            runStore.save(run.runId);
        },
        onNodeComplete: (nodeId, result) => {
            console.log((0, progress_js_1.formatNodeStatus)(nodeId, 'completed', result.durationMs));
            runStore.updateNode(run.runId, nodeId, result);
            runStore.save(run.runId);
        },
        onNodeSkip: (nodeId, _reason) => {
            console.log((0, progress_js_1.formatNodeStatus)(nodeId, 'skipped'));
            runStore.updateNode(run.runId, nodeId, { status: 'skipped' });
            runStore.save(run.runId);
        },
        onNodeFail: (nodeId, error) => {
            console.log((0, progress_js_1.formatNodeStatus)(nodeId, 'failed'));
            runStore.updateNode(run.runId, nodeId, { status: 'failed', error });
            runStore.save(run.runId);
        },
    };
    const executor = new core_1.DAGExecutor(ws.sourcePath, projectPath, graph, callbacks);
    // Step loop — for bash-only workflows, this completes in one call
    let step;
    try {
        step = await executor.step({ args, artifactsDir: ws.artifactsPath });
        if (step.type === 'needs_ai') {
            throw new Error('Unexpected AI node in bash-only workflow');
        }
    }
    catch (err) {
        try {
            runStore.fail(run.runId);
        }
        catch { /* best-effort */ }
        try {
            runStore.appendHistory(run.runId);
        }
        catch { /* best-effort */ }
        try {
            await wsManager.destroy(ws.id);
        }
        catch { /* best-effort */ }
        throw err;
    }
    const totalMs = Date.now() - startTime;
    const success = step.type === 'done';
    console.log((0, progress_js_1.formatSummary)(success, totalMs));
    if (success) {
        const diff = await wsManager.diff(ws.id);
        if (diff.modified.length > 0 || diff.added.length > 0) {
            console.log('\n[vsaf] Changed files:');
            for (const f of diff.modified)
                console.log(`  M ${f}`);
            for (const f of diff.added)
                console.log(`  A ${f}`);
            await wsManager.applyChanges(ws.id);
            console.log('[vsaf] Changes applied to project.');
        }
        runStore.complete(run.runId);
        try {
            runStore.appendHistory(run.runId);
        }
        catch { /* best-effort */ }
        await wsManager.destroy(ws.id);
        console.log(`[vsaf] Workspace cleaned up`);
    }
    else {
        runStore.fail(run.runId);
        try {
            runStore.appendHistory(run.runId);
        }
        catch { /* best-effort */ }
        console.log(`\n[vsaf] Run ID: ${run.runId}`);
        console.log(`[vsaf] Workspace preserved at: ${ws.sourcePath}`);
    }
}
//# sourceMappingURL=run.js.map