/**
 * 变异审计真实化 — 需求绑定变异点 + mutant killed 证据。
 *
 * 门禁硬化（Batch 2）：
 * - P0/P1 需求点变异覆盖 = 0 → hard_fail
 * - 整体变异覆盖率 < 50% → warning
 * - 未绑定需求点的变异点 > 30% → warning
 *
 * 职责:
 * - computeMutationAudit: 从变更文件 + 需求点 + 源码计算变异证据
 * - 产出 MutationAuditEvidence: mutant_killed_count / mutant_total_count / per-requirement 绑定
 */
import { debug } from "../core/logger.js";
const CANDIDATE_PATTERNS = [
    /\b(if|else|switch|case)\b/.source,
    /(===|!==|==|!=|>=|<=|>|<)/.source,
    /(&&|\|\|)/.source,
    /\breturn\b/.source,
];
const CANDIDATE_RE = new RegExp(CANDIDATE_PATTERNS.join("|"));
const EXCLUDE_PATTERNS = [
    /^\s*\/\//,
    /^\s*\*/,
    /^\s*\/\*/,
    /^\s*import /,
    /^\s*export /,
    /^\s*console\./,
    /^\s*(interface|type|enum|declare) /,
    /^\s*debugger/,
];
function isCandidateLine(line) {
    const trimmed = line.trim();
    if (!trimmed)
        return false;
    if (EXCLUDE_PATTERNS.some((p) => p.test(trimmed)))
        return false;
    return CANDIDATE_RE.test(trimmed);
}
/**
 * 从源码中提取变异候选点，并尝试关联到需求点。
 * 关联策略: 文件路径与需求点描述关键词匹配。
 *
 * @param sourceFiles - 源文件列表，包含文件路径和内容
 * @param requirementPoints - 需求点列表
 * @returns 变异候选点数组
 */
export function extractMutationPoints(sourceFiles, requirementPoints) {
    const points = [];
    debug("变异审计", "extractMutationPoints() 开始执行，源文件数:", sourceFiles.length, "，需求点数:", requirementPoints.length);
    for (const file of sourceFiles) {
        const lines = file.content.split("\n");
        for (let i = 0; i < lines.length; i++) {
            if (!isCandidateLine(lines[i]))
                continue;
            const matchedRp = requirementPoints.find((rp) => {
                const keywords = rp.description.toLowerCase().split(/\s+/);
                return keywords.some((kw) => kw.length > 2 && file.file_path.toLowerCase().includes(kw));
            });
            points.push({
                file_path: file.file_path,
                line_number: i + 1,
                original_line: lines[i].trim(),
                requirement_point_id: matchedRp?.id,
            });
        }
    }
    debug("变异审计", "提取到变异候选点", points.length, "个");
    return points;
}
/**
 * 计算变异审计证据 — 每个需求点的变异覆盖状态。
 *
 * @param mutationPoints - 变异候选点数组
 * @param requirementPoints - 需求点列表
 * @param killedCount - 已 killed 的变异数
 * @param totalCount - 变异总数
 * @returns 变异审计证据
 */
export function computeMutationAudit(mutationPoints, requirementPoints, killedCount, totalCount) {
    const perRequirement = [];
    const coveredRpIds = new Set();
    debug("变异审计", "computeMutationAudit() 开始执行，需求点数:", requirementPoints.length, "变异点数:", mutationPoints.length, "killed:", killedCount, "/", totalCount);
    for (const rp of requirementPoints) {
        const rpPoints = mutationPoints.filter((mp) => mp.requirement_point_id === rp.id);
        const rpTotal = rpPoints.length;
        if (rpTotal > 0) {
            coveredRpIds.add(rp.id);
            // 按比例分配 killed 计数
            const rpKilled = Math.min(Math.round((rpTotal / Math.max(totalCount, 1)) * killedCount), rpTotal);
            perRequirement.push({
                requirement_point_id: rp.id,
                mutation_points: rpTotal,
                mutants_killed: rpKilled,
                mutants_total: rpTotal,
                advisory: rpKilled === rpTotal
                    ? "all mutants killed"
                    : `advisory: ${rpTotal - rpKilled}/${rpTotal} mutants not killed for ${rp.id}`,
                // 门禁硬化：P0/P1 需求点变异覆盖 = 0 → hard_fail
                severity: rpKilled === 0 ? "hard_fail" : undefined,
            });
        }
        else {
            perRequirement.push({
                requirement_point_id: rp.id,
                mutation_points: 0,
                mutants_killed: 0,
                mutants_total: 0,
                advisory: `advisory: no mutation points found for requirement ${rp.id}`,
                // 无变异点 → 暂不标记严重性（可能该需求不涉及代码变更）
            });
        }
    }
    // 同时包含未绑定到任何需求点的变异点
    const unboundPoints = mutationPoints.filter((mp) => !mp.requirement_point_id);
    const unboundRatio = totalCount > 0 ? unboundPoints.length / totalCount : 0;
    if (unboundPoints.length > 0) {
        perRequirement.push({
            requirement_point_id: "_unbound",
            mutation_points: unboundPoints.length,
            mutants_killed: 0,
            mutants_total: unboundPoints.length,
            advisory: `advisory: ${unboundPoints.length} mutation points not bound to any requirement`,
            // 门禁硬化：未绑定 > 30% → warning
            severity: unboundRatio > 0.3 ? "warning" : undefined,
        });
    }
    const uncoveredRequirements = requirementPoints
        .filter((rp) => !coveredRpIds.has(rp.id))
        .map((rp) => rp.id);
    if (uncoveredRequirements.length > 0) {
        debug("变异审计", "发现未覆盖的需求点:", uncoveredRequirements.join(", "));
    }
    const killRatio = totalCount > 0 ? killedCount / totalCount : 1;
    debug("变异审计", "计算完成 — kill_ratio:", (killRatio * 100).toFixed(0) + "%", "，未覆盖需求:", uncoveredRequirements.length);
    // ── 门禁硬化汇总 ──
    const hardFailCount = perRequirement.filter((e) => e.severity === "hard_fail").length;
    const warningCount = perRequirement.filter((e) => e.severity === "warning").length;
    // 整体变异覆盖率 < 50% → 额外 warning
    const lowCoverage = totalCount > 0 && killRatio < 0.5;
    return {
        mutant_killed_count: killedCount,
        mutant_total_count: totalCount,
        kill_ratio: killRatio,
        per_requirement: perRequirement,
        uncovered_requirements: uncoveredRequirements,
        summary: uncoveredRequirements.length > 0
            ? `advisory: ${uncoveredRequirements.length} requirement(s) have no killed mutants: ${uncoveredRequirements.join(", ")}`
            : `mutation audit: ${killedCount}/${totalCount} killed (ratio: ${(killRatio * 100).toFixed(0)}%)`,
        hard_fail_count: hardFailCount,
        warning_count: warningCount + (lowCoverage ? 1 : 0),
    };
}
//# sourceMappingURL=mutation_audit.js.map