// engine/hooks/handlers/on-test-pass.ts — on-test-pass hook handler (SPEC-130)
// Watches coverage-summary.json, extracts coverage delta, maps to specs.
import { readFile } from 'node:fs/promises';
// ---------------------------------------------------------------------------
// In-memory previous coverage cache
// ---------------------------------------------------------------------------
const previousCoverageCache = new Map();
/**
 * Get previous coverage cache (for testing).
 */
export function getPreviousCoverage(coveragePath) {
    return previousCoverageCache.get(coveragePath);
}
/**
 * Clear previous coverage cache (for testing).
 */
export function clearPreviousCoverage() {
    previousCoverageCache.clear();
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
/**
 * Parse coverage-summary.json and extract per-file line coverage percentage.
 */
export async function parseCoverageSummary(coveragePath) {
    const raw = await readFile(coveragePath, 'utf-8');
    const summary = JSON.parse(raw);
    const result = {};
    for (const [filePath, coverage] of Object.entries(summary)) {
        if (filePath === 'total') {
            continue;
        }
        const pct = coverage.lines?.pct;
        if (typeof pct === 'number') {
            result[filePath] = pct;
        }
    }
    return result;
}
/**
 * Compute coverage delta per file.
 */
export function computeCoverageDelta(current, previous) {
    const delta = {};
    for (const [file, pct] of Object.entries(current)) {
        const prev = previous[file] ?? 0;
        const diff = pct - prev;
        if (Math.abs(diff) > 0.001) {
            delta[file] = Math.round(diff * 100) / 100;
        }
    }
    return delta;
}
/**
 * Map coverage files to spec IDs via annotation index.
 */
export function mapFilesToSpecs(files, annotationIndex) {
    const specIds = new Set();
    for (const file of files) {
        for (const entry of annotationIndex) {
            if (entry.annotatedFiles.some((af) => file.includes(af) || af.includes(file))) {
                specIds.add(entry.specId);
            }
        }
    }
    return [...specIds];
}
// ---------------------------------------------------------------------------
// Handler
// ---------------------------------------------------------------------------
/**
 * Handle on-test-pass event.
 * - Reads coverage-summary.json
 * - Computes coverage delta per file
 * - Maps changed files to specs via annotations
 * - Returns coverage delta and updated specs
 */
export async function handleOnTestPass(ctx) {
    let current;
    try {
        current = await parseCoverageSummary(ctx.coveragePath);
    }
    catch {
        return {
            hook: 'on-test-pass',
            coverageDelta: {},
            specsUpdated: [],
        };
    }
    // Get previous coverage
    const previous = ctx.previousCoverage ?? previousCoverageCache.get(ctx.coveragePath) ?? {};
    // Compute delta
    const coverageDelta = computeCoverageDelta(current, previous);
    // Update cache for next run
    previousCoverageCache.set(ctx.coveragePath, current);
    // Map files with coverage changes to specs
    const changedFiles = Object.keys(coverageDelta);
    const specsUpdated = mapFilesToSpecs(changedFiles, ctx.specAnnotationIndex);
    return {
        hook: 'on-test-pass',
        coverageDelta,
        specsUpdated,
    };
}
//# sourceMappingURL=on-test-pass.js.map