/**
 * pipeline/plan-format.ts
 *
 * Formatters for rendering an ExecutionPlan to console output or JSON.
 *
 * The console formatter produces a rich, human-readable preview with
 * emoji markers, alignment, and color-coding (via unicode markers).
 * The JSON formatter produces machine-readable output for CI/CD.
 *
 * @see docs/archive/exec-plans/execution-preview.md
 */
import { formatCost } from "../agent-observer/pricing.js";
// ---------------------------------------------------------------------------
// Duration formatting
// ---------------------------------------------------------------------------
/**
 * Format an execution plan as a rich console string.
 *
 * Produces a multi-section output with emoji markers showing:
 * - Command summary (mode, source, flags)
 * - Step plan (which steps will run, cached, or skipped)
 * - Test/task summary
 * - Model list
 * - Cost estimate
 * - File I/O
 * - Comparison context
 * - Warnings/errors
 */
export function formatPlanConsole(plan) {
    const lines = [];
    // Header
    lines.push(`📋 Execution Plan: ailf ${plan.command}`);
    lines.push("");
    // Command summary
    if (plan.mode) {
        lines.push(`  Mode:         ${plan.mode}`);
    }
    if (plan.source) {
        lines.push(`  Source:       ${plan.source}${plan.source === "production" ? " (sanity.io/docs)" : ""}`);
    }
    lines.push("");
    // Step plan
    if (plan.steps.length > 0) {
        const willRunCount = plan.steps.filter((s) => s.willRun).length;
        const totalSteps = plan.steps.length;
        lines.push(`  📦 Steps (${willRunCount} of ${totalSteps} will execute):`);
        for (const step of plan.steps) {
            const icon = stepIcon(step);
            const suffix = step.cacheStatus === "hit" && step.estimatedSavedMs
                ? ` (saving ~${formatDuration(step.estimatedSavedMs)})`
                : "";
            lines.push(`    ${icon} ${step.name} — ${step.reason}${suffix}`);
        }
        lines.push("");
    }
    // Test/task summary
    if (plan.totalTests !== undefined) {
        if (plan.debug) {
            lines.push(`  🧪 Tests: ${plan.debug.filteredCount} of ${plan.debug.totalCount} (${plan.debug.filterDescription})`);
        }
        else {
            lines.push(`  🧪 Tests: ${plan.totalTests}`);
        }
        if (plan.repoTaskCount && plan.repoTaskCount > 0) {
            lines.push(`  (includes ${plan.repoTaskCount} repo-based task definition${plan.repoTaskCount === 1 ? "" : "s"})`);
        }
        // Show task list (gold variants only, to avoid duplication noise)
        if (plan.tasks && plan.tasks.length > 0) {
            const goldTasks = plan.tasks.filter((t) => t.variant === "gold");
            const maxShow = 15;
            const showTasks = goldTasks.slice(0, maxShow);
            for (const task of showTasks) {
                lines.push(`    • ${task.description}`);
            }
            if (goldTasks.length > maxShow) {
                lines.push(`    … and ${goldTasks.length - maxShow} more`);
            }
        }
        lines.push("");
    }
    // Model list
    if (plan.models && plan.models.length > 0) {
        lines.push(`  🤖 Models (${plan.models.length}):`);
        const maxLabelLen = Math.max(...plan.models.map((m) => m.label.length));
        for (const model of plan.models) {
            const padded = model.label.padEnd(maxLabelLen + 2);
            lines.push(`    ${padded} ${model.id}`);
        }
        lines.push("");
    }
    // Cost estimate
    if (plan.costEstimate) {
        const ce = plan.costEstimate;
        lines.push(`  📊 Estimated API calls: ${ce.totalApiCalls} (${plan.totalTests ?? 0} tests × ${plan.models?.length ?? 0} models)`);
        const minCost = formatCost(ce.totalCost.min);
        const maxCost = formatCost(ce.totalCost.max);
        const gradingMin = formatCost(ce.grading.min);
        const gradingMax = formatCost(ce.grading.max);
        lines.push(`  💰 Estimated cost:      ${minCost}–${maxCost} (includes ${gradingMin}–${gradingMax} grading)`);
        // Per-model breakdown
        if (ce.perModel.length > 1) {
            for (const pm of ce.perModel) {
                if (pm.cost.min > 0) {
                    lines.push(`     └ ${pm.label}: ${formatCost(pm.cost.min)}–${formatCost(pm.cost.max)}`);
                }
            }
        }
        lines.push("");
    }
    // Cache savings
    if (plan.totalCacheSavingsMs > 0) {
        lines.push(`  ⏱️  Cache savings:       ~${formatDuration(plan.totalCacheSavingsMs)} from cached steps`);
        lines.push("");
    }
    // Comparison
    if (plan.comparison) {
        lines.push("  📊 Comparison:");
        const ageStr = plan.comparison.baselineAge
            ? ` (${plan.comparison.baselineAge} old)`
            : "";
        const existsStr = plan.comparison.exists ? "" : " ⚠️  NOT FOUND";
        lines.push(`    Baseline:  ${plan.comparison.baselinePath}${ageStr}${existsStr}`);
        lines.push(`    Threshold: ±${plan.comparison.threshold} points`);
        lines.push("");
    }
    // Files read
    if (plan.filesRead.length > 0) {
        lines.push(`  📂 Files read (${plan.filesRead.length}):`);
        const maxShow = 10;
        const shown = plan.filesRead.slice(0, maxShow);
        lines.push(`    ${shown.join(", ")}`);
        if (plan.filesRead.length > maxShow) {
            lines.push(`    … and ${plan.filesRead.length - maxShow} more`);
        }
        lines.push("");
    }
    // Files created
    if (plan.filesCreated.length > 0) {
        lines.push(`  📝 Files created:`);
        for (const f of plan.filesCreated) {
            lines.push(`    ${f}`);
        }
        lines.push("");
    }
    // Warnings
    if (plan.warnings.length > 0) {
        lines.push(`  ⚠️  Warnings (${plan.warnings.length}):`);
        for (const w of plan.warnings) {
            lines.push(`    ${w}`);
        }
        lines.push("");
    }
    // Errors
    if (plan.errors.length > 0) {
        lines.push(`  ❌ Errors (${plan.errors.length}):`);
        for (const e of plan.errors) {
            lines.push(`    ${e}`);
        }
        lines.push("");
    }
    // Footer
    lines.push("  Run without --explain to execute, or add --yes to preview then confirm.");
    lines.push("");
    return lines.join("\n");
}
// ---------------------------------------------------------------------------
// Console formatter
// ---------------------------------------------------------------------------
/**
 * Format an execution plan as indented JSON.
 *
 * Useful for CI/CD integration, approval gates, and programmatic
 * inspection of the plan.
 */
export function formatPlanJson(plan) {
    return JSON.stringify(plan, null, 2);
}
// ---------------------------------------------------------------------------
// JSON formatter
// ---------------------------------------------------------------------------
function formatDuration(ms) {
    if (ms < 1000)
        return `${ms}ms`;
    if (ms < 60000)
        return `${(ms / 1000).toFixed(1)}s`;
    const min = Math.floor(ms / 60000);
    const sec = Math.round((ms % 60000) / 1000);
    return `${min}m ${sec}s`;
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function stepIcon(step) {
    if (!step.willRun) {
        if (step.cacheStatus === "hit")
            return "📦";
        if (step.cacheStatus === "skipped")
            return "⏭️";
        return "⏭️";
    }
    return "✅";
}
