import { extractTopLevelSection, IMPLEMENTATION_CONTRACT_SECTION, IMPLEMENTATION_CONTRACT_SUBSECTIONS, } from './common.js';
const FILLER_PATTERNS = [
    /\bTBD\b/i,
    /\bN\/A\b/i,
    /\bimplement correctly\b/i,
    /\bhandle errors\b/i,
    /\bto be determined\b/i,
];
export function evaluateImplementationContract(specBody, acceptanceCriteria) {
    const contract = extractTopLevelSection(specBody, IMPLEMENTATION_CONTRACT_SECTION);
    if (contract.trim().length === 0) {
        return [
            {
                code: 'contract_missing',
                message: 'Implementation Contract is missing — add user outcome, behavior, file plan, verification map, edge cases, non-goals, and commands.',
            },
        ];
    }
    const issues = [];
    const sections = new Map(IMPLEMENTATION_CONTRACT_SUBSECTIONS.map((section) => [
        section,
        extractSubsection(contract, section),
    ]));
    for (const [section, content] of sections.entries()) {
        if (content === null) {
            issues.push({
                code: 'contract_subsection_missing',
                message: `Implementation Contract subsection "${section}" is missing.`,
            });
            continue;
        }
        const trimmed = content.trim();
        if (trimmed.length === 0) {
            issues.push({
                code: 'contract_subsection_empty',
                message: `Implementation Contract subsection "${section}" is empty.`,
            });
        }
        for (const pattern of FILLER_PATTERNS) {
            if (pattern.test(trimmed)) {
                issues.push({
                    code: 'contract_filler',
                    message: `Implementation Contract subsection "${section}" contains filler text.`,
                });
                break;
            }
        }
        if (/\bNeeds decision:/i.test(trimmed)) {
            issues.push({
                code: 'contract_needs_decision',
                message: `Implementation Contract subsection "${section}" still has unresolved Needs decision items.`,
            });
        }
    }
    const map = sections.get('Acceptance-To-Verification Map') ?? '';
    for (const criterion of acceptanceCriteria) {
        if (!criterionHasVerification(criterion, map)) {
            issues.push({
                code: 'contract_unmapped_criterion',
                message: `Acceptance criterion is not mapped to verification evidence: ${criterion}`,
            });
        }
    }
    if (/\bmanual verification\b/i.test(map) &&
        !/\b(given|when|then|step|observe|click|run)\b/i.test(map)) {
        issues.push({
            code: 'contract_manual_verification_vague',
            message: 'Manual verification in the Implementation Contract must include exact observable steps.',
        });
    }
    return issues;
}
function extractSubsection(sectionBody, subsectionName) {
    const headingRe = new RegExp(`^###\\s+${escapeRegex(subsectionName)}[ \\t]*$`, 'm');
    const match = headingRe.exec(sectionBody);
    if (!match) {
        return null;
    }
    const start = match.index + match[0].length;
    const nextRe = /^###\s+\S/gm;
    nextRe.lastIndex = start;
    const next = nextRe.exec(sectionBody);
    return sectionBody.slice(start, next ? next.index : sectionBody.length);
}
function criterionHasVerification(criterion, map) {
    const normalizedCriterion = normalize(criterion);
    if (normalizedCriterion.length === 0) {
        return true;
    }
    const short = normalizedCriterion.slice(0, 48);
    const normalizedMap = normalize(map);
    return (normalizedMap.includes(short) &&
        /\b(unit test|integration test|cli\/tool result|typecheck\/lint command|snapshot\/golden fixture|manual verification|pnpm|vitest|test)\b/i.test(map));
}
function normalize(value) {
    return value
        .replace(/[`*_()[\]:]/g, ' ')
        .replace(/\s+/g, ' ')
        .trim()
        .toLowerCase();
}
function escapeRegex(input) {
    return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
//# sourceMappingURL=evaluator.js.map