// engine/config-health/ci-version-checker.ts — SPEC-042
// Version consistency checks between CI files and local tool-version declarations.
import { join } from 'node:path';
import { glob } from 'glob';
import { readFileSafe } from './ci-commands-collector.js';
async function collectVersionDeclarations(projectPath) {
    const declarations = [];
    const nvmrc = await readFileSafe(join(projectPath, '.nvmrc'));
    if (nvmrc.trim()) {
        declarations.push({
            runtime: 'node',
            version: nvmrc.trim().replace('v', ''),
            source: '.nvmrc',
        });
    }
    const toolVersions = await readFileSafe(join(projectPath, '.tool-versions'));
    if (toolVersions) {
        for (const line of toolVersions.split('\n')) {
            const m = /^(nodejs|python|go|rust|ruby)\s+([\d.]+)/.exec(line.trim());
            if (m?.[1] && m[2]) {
                const runtime = m[1] === 'nodejs' ? 'node' : m[1];
                declarations.push({ runtime, version: m[2], source: '.tool-versions' });
            }
        }
    }
    const goMod = await readFileSafe(join(projectPath, 'go.mod'));
    if (goMod) {
        const m = /^go\s+([\d.]+)/m.exec(goMod);
        if (m?.[1]) {
            declarations.push({ runtime: 'go', version: m[1], source: 'go.mod' });
        }
    }
    const pyproject = await readFileSafe(join(projectPath, 'pyproject.toml'));
    if (pyproject) {
        const m = /requires-python\s*=\s*"([^"]+)"/.exec(pyproject);
        if (m?.[1]) {
            const version = m[1]
                .replace(/[>=<~!]/g, '')
                .trim()
                .split('.')
                .slice(0, 2)
                .join('.');
            declarations.push({ runtime: 'python', version, source: 'pyproject.toml' });
        }
    }
    return declarations;
}
function checkVersionInCiFile(content, ciFile, localVersions) {
    const findings = [];
    const nodeVersionPattern = /node-version\s*:\s*['"]?([\d.]+)['"]?/g;
    let match;
    while ((match = nodeVersionPattern.exec(content)) !== null) {
        /* v8 ignore start */
        const ciVersion = (match[1] ?? '').split('.')[0] ?? '';
        /* v8 ignore stop */
        const localNode = localVersions.find((v) => v.runtime === 'node');
        const localMajor = localNode?.version.split('.')[0] ?? '';
        if (localNode && ciVersion && localMajor && ciVersion !== localMajor) {
            findings.push({
                severity: 'warning',
                checker: 'ci-commands',
                file: ciFile,
                message: `CI uses Node.js ${ciVersion} but ${localNode.source} specifies ${localNode.version}`,
                fix: `Align Node.js version in ${ciFile} with ${localNode.source} (use ${localNode.version})`,
            });
        }
    }
    const pythonVersionPattern = /python-version\s*:\s*['"]?([\d.]+)['"]?/g;
    while ((match = pythonVersionPattern.exec(content)) !== null) {
        const ciVersion = match[1];
        const localPython = localVersions.find((v) => v.runtime === 'python');
        if (localPython && ciVersion) {
            const ciMM = ciVersion.split('.').slice(0, 2).join('.');
            const localMM = localPython.version.split('.').slice(0, 2).join('.');
            if (ciMM !== localMM) {
                findings.push({
                    severity: 'warning',
                    checker: 'ci-commands',
                    file: ciFile,
                    message: `CI uses Python ${ciVersion} but ${localPython.source} specifies ${localPython.version}`,
                    fix: `Align Python version in ${ciFile} with ${localPython.source} (use ${localPython.version})`,
                });
            }
        }
    }
    const goVersionPattern = /go-version\s*:\s*['"]?([\d.]+)['"]?/g;
    while ((match = goVersionPattern.exec(content)) !== null) {
        const ciVersion = match[1];
        const localGo = localVersions.find((v) => v.runtime === 'go');
        if (localGo && ciVersion) {
            const ciMM = ciVersion.split('.').slice(0, 2).join('.');
            const localMM = localGo.version.split('.').slice(0, 2).join('.');
            if (ciMM !== localMM) {
                findings.push({
                    severity: 'warning',
                    checker: 'ci-commands',
                    file: ciFile,
                    message: `CI uses Go ${ciVersion} but ${localGo.source} specifies ${localGo.version}`,
                    fix: `Align Go version in ${ciFile} with ${localGo.source} (use ${localGo.version})`,
                });
            }
        }
    }
    return findings;
}
export async function checkVersionConsistency(projectPath) {
    const findings = [];
    const localVersions = await collectVersionDeclarations(projectPath);
    if (localVersions.length === 0) {
        return findings;
    }
    let ciFiles;
    try {
        ciFiles = await glob('.github/workflows/*.{yml,yaml}', { cwd: projectPath, nodir: true });
    }
    catch {
        return findings;
    }
    if (ciFiles.length === 0) {
        return findings;
    }
    for (const ciFile of ciFiles) {
        const content = await readFileSafe(join(projectPath, ciFile));
        if (!content) {
            continue;
        }
        findings.push(...checkVersionInCiFile(content, ciFile, localVersions));
    }
    return findings;
}
//# sourceMappingURL=ci-version-checker.js.map