// engine/plan-mode/plan-builder.ts — Builds a PlanPreview from a Spec (SPEC-473)
import { existsSync } from 'node:fs';
import { readSpecTechnicalSection } from '../spec-format/read-technical-section.js';
import { randomUUID } from 'node:crypto';
import { estimateLinesForFile, inferFileRisk } from './diff-estimator.js';
// ---------------------------------------------------------------------------
// Technical file extraction
// ---------------------------------------------------------------------------
/** Parse file paths listed in a technical.md "## Files" section. */
function extractFilesFromTechnical(content) {
    const lines = content.split('\n');
    const files = [];
    let inFilesSection = false;
    for (const line of lines) {
        if (/^#+\s+files/i.test(line)) {
            inFilesSection = true;
            continue;
        }
        if (inFilesSection && /^#+\s/.test(line)) {
            inFilesSection = false;
            continue;
        }
        if (inFilesSection) {
            // Match lines like: - `src/foo/bar.ts`, * src/baz.ts, or bare paths
            const match = /[`*\-\s]*([a-zA-Z0-9_./@-]+\.[a-zA-Z]{1,6})/u.exec(line);
            if (match?.[1]) {
                files.push(match[1]);
            }
        }
    }
    return files;
}
// ---------------------------------------------------------------------------
// Risk aggregation
// ---------------------------------------------------------------------------
function computeOverallRisk(files) {
    if (files.some((f) => f.riskLevel === 'high')) {
        return 'high';
    }
    if (files.some((f) => f.riskLevel === 'medium')) {
        return 'medium';
    }
    return 'low';
}
// ---------------------------------------------------------------------------
// Warnings
// ---------------------------------------------------------------------------
function buildWarnings(files) {
    const warnings = [];
    const highRisk = files.filter((f) => f.riskLevel === 'high');
    if (highRisk.length > 0) {
        warnings.push(`${highRisk.length} high-risk file(s) detected — review carefully before implementing.`);
    }
    const deletes = files.filter((f) => f.action === 'delete');
    if (deletes.length > 0) {
        warnings.push(`${deletes.length} file(s) marked for deletion — ensure no remaining references.`);
    }
    const totalAdded = files.reduce((sum, f) => sum + f.estimatedLinesAdded, 0);
    if (totalAdded > 300) {
        warnings.push('Large implementation scope (>300 estimated lines) — consider splitting the spec.');
    }
    return warnings;
}
// ---------------------------------------------------------------------------
// Public builder
// ---------------------------------------------------------------------------
/** Build a PlanPreview from a resolved Spec. */
export async function buildPlanFromSpec(spec) {
    const specRisk = spec.risk;
    // Read technical content from unified spec.md (## Technical section) with legacy fallback
    const technicalContent = await readSpecTechnicalSection(spec);
    const rawFiles = extractFilesFromTechnical(technicalContent);
    // Build FilePlan entries
    const files = rawFiles.map((filePath) => {
        const fileExists = existsSync(filePath);
        const action = fileExists ? 'modify' : 'create';
        const { added, removed } = estimateLinesForFile(filePath, action);
        const riskLevel = inferFileRisk(filePath, specRisk);
        return {
            path: filePath,
            action,
            estimatedLinesAdded: added,
            estimatedLinesRemoved: removed,
            riskLevel,
            reason: action === 'create'
                ? `New file required by ${spec.id}`
                : `Existing file modified by ${spec.id}`,
        };
    });
    const totalLinesAdded = files.reduce((sum, f) => sum + f.estimatedLinesAdded, 0);
    const totalLinesRemoved = files.reduce((sum, f) => sum + f.estimatedLinesRemoved, 0);
    const preview = {
        planId: randomUUID(),
        specId: spec.id,
        createdAt: new Date().toISOString(),
        files,
        summary: {
            totalFiles: files.length,
            filesToCreate: files.filter((f) => f.action === 'create').length,
            filesToModify: files.filter((f) => f.action === 'modify').length,
            filesToDelete: files.filter((f) => f.action === 'delete').length,
            estimatedLinesAdded: totalLinesAdded,
            estimatedLinesRemoved: totalLinesRemoved,
            overallRisk: computeOverallRisk(files),
        },
        warnings: buildWarnings(files),
    };
    return preview;
}
//# sourceMappingURL=plan-builder.js.map