// engine/spec-health-scorer.ts — Real-time spec health score (SPEC-571)
// Pure synchronous function: no I/O, no external deps.
// ── Constants ────────────────────────────────────────────────────────────────
const BDD_PATTERN = /\b(given|when|then)\b/i;
// ── Internal helpers ─────────────────────────────────────────────────────────
function gradeFromScore(score) {
    if (score >= 80) {
        return 'A';
    }
    if (score >= 65) {
        return 'B';
    }
    if (score >= 50) {
        return 'C';
    }
    if (score >= 35) {
        return 'D';
    }
    return 'F';
}
/**
 * Extract acceptance criteria lines from in-memory spec.
 * Criteria are stored as an array of strings in the lean spec format.
 * Uses unknown cast to handle both lean and legacy formats without
 * modifying the strict Spec interface.
 */
function extractCriteria(spec) {
    const raw = spec.criteria;
    if (Array.isArray(raw)) {
        return raw.filter((c) => typeof c === 'string');
    }
    return [];
}
// ── Dimension scorers ────────────────────────────────────────────────────────
/** 0-20 pts based on acceptance criteria count + BDD bonus. */
function scoreCriteriaCount(criteria) {
    const count = criteria.length;
    let pts;
    if (count === 0) {
        pts = 0;
    }
    else if (count <= 2) {
        pts = 10;
    }
    else if (count <= 4) {
        pts = 15;
    }
    else {
        pts = 20;
    }
    // Bonus: if any criterion contains a GIVEN/WHEN/THEN pattern and pts < 20
    if (pts < 20 && criteria.some((c) => BDD_PATTERN.test(c))) {
        pts = Math.min(20, pts + 5);
    }
    return pts;
}
/** 0-20 pts: devHours>0 AND cost>0 → 20; only one → 10; none → 0. */
function scoreEstimationConfidence(spec) {
    const estimation = spec.estimation;
    const devHours = estimation?.devHours ?? 0;
    const cost = estimation?.cost ?? 0;
    const hasDev = devHours > 0;
    const hasCost = cost > 0;
    if (hasDev && hasCost) {
        return 20;
    }
    if (hasDev || hasCost) {
        return 10;
    }
    return 0;
}
/** 0-20 pts: tags.length>0 → 5, gitBranch → 5, difficulty set → 5, risk set → 5. */
function scoreTechnicalDetail(spec) {
    let pts = 0;
    if (spec.tags.length > 0) {
        pts += 5;
    }
    const branch = spec.gitBranch;
    if (branch && branch.trim().length > 0) {
        pts += 5;
    }
    // difficulty is Difficulty (1|2|3|4|5) — any truthy non-zero value means it is set
    const difficulty = spec.difficulty;
    if (difficulty !== undefined && difficulty !== 'unknown' && difficulty !== 0) {
        pts += 5;
    }
    const risk = spec.risk;
    if (risk && risk !== 'unknown' && risk.trim().length > 0) {
        pts += 5;
    }
    return pts;
}
/** 0-20 pts: count criteria with GIVEN/WHEN/THEN. ≥2→20, 1→10, 0→0. */
function scoreBddTestability(criteria) {
    const bddCount = criteria.filter((c) => BDD_PATTERN.test(c)).length;
    if (bddCount >= 2) {
        return 20;
    }
    if (bddCount === 1) {
        return 10;
    }
    return 0;
}
/** 0-20 pts: tags.length ≥ 3 → 20, 2 → 15, 1 → 10, 0 → 0. */
function scoreTagsCoverage(spec) {
    const count = spec.tags.length;
    if (count >= 3) {
        return 20;
    }
    if (count === 2) {
        return 15;
    }
    if (count === 1) {
        return 10;
    }
    return 0;
}
// ── Public API ───────────────────────────────────────────────────────────────
/**
 * Compute a real-time health score for a spec.
 * Pure function — no I/O, no side effects.
 */
export function computeHealthScore(spec, criteria) {
    const criteriaLines = criteria ?? extractCriteria(spec);
    const criteriaCount = scoreCriteriaCount(criteriaLines);
    const estimationConfidence = scoreEstimationConfidence(spec);
    const technicalDetail = scoreTechnicalDetail(spec);
    const bddTestability = scoreBddTestability(criteriaLines);
    const tagsCoverage = scoreTagsCoverage(spec);
    const score = criteriaCount + estimationConfidence + technicalDetail + bddTestability + tagsCoverage;
    return {
        score,
        dimensions: {
            criteriaCount,
            estimationConfidence,
            technicalDetail,
            bddTestability,
            tagsCoverage,
        },
        grade: gradeFromScore(score),
    };
}
//# sourceMappingURL=spec-health-scorer.js.map