// engine/project-scanner/convention-detector.ts — Sample files to detect code conventions
import { readFile } from 'node:fs/promises';
import { glob } from 'glob';
const MAX_SAMPLE_LINES = 200;
const MAX_SAMPLE_FILES = 5;
function classifyName(name) {
    if (/^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(name)) {
        return 'kebab-case';
    }
    if (/^[a-z][a-zA-Z0-9]*$/.test(name) && /[A-Z]/.test(name)) {
        return 'camelCase';
    }
    if (/^[A-Z][a-zA-Z0-9]*$/.test(name)) {
        return 'PascalCase';
    }
    if (/^[a-z][a-z0-9]*(_[a-z0-9]+)+$/.test(name)) {
        return 'snake_case';
    }
    return null;
}
function majority(votes) {
    if (votes.length === 0) {
        return 'unknown';
    }
    const counts = new Map();
    for (const v of votes) {
        counts.set(v, (counts.get(v) ?? 0) + 1);
    }
    let best = 'unknown';
    let bestCount = 0;
    for (const [style, count] of counts) {
        if (count > bestCount) {
            bestCount = count;
            best = style;
        }
    }
    return best;
}
async function detectFileNaming(projectPath) {
    try {
        const files = await glob('src/**/*.{ts,js,tsx,jsx,py,go}', {
            cwd: projectPath,
            absolute: false,
        });
        const votes = [];
        for (const f of files.slice(0, 30)) {
            const base = f.split('/').pop() ?? '';
            const nameWithoutExt = base.replace(/\.[^.]+$/, '');
            const style = classifyName(nameWithoutExt);
            if (style) {
                votes.push(style);
            }
        }
        return majority(votes);
    }
    catch {
        return 'unknown';
    }
}
async function sampleSourceFiles(projectPath) {
    try {
        const files = await glob('src/**/*.{ts,js}', { cwd: projectPath, absolute: true });
        return files.slice(0, MAX_SAMPLE_FILES);
    }
    catch {
        return [];
    }
}
async function readFirstLines(filePath) {
    try {
        const content = await readFile(filePath, 'utf-8');
        return content.split('\n').slice(0, MAX_SAMPLE_LINES).join('\n');
    }
    catch {
        return '';
    }
}
function detectFunctionNaming(content) {
    const fnMatches = [
        ...content.matchAll(/function\s+([a-zA-Z_][a-zA-Z0-9_]*)/g),
        ...content.matchAll(/(?:const|let|var)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(?:async\s*)?\(/g),
    ];
    const names = fnMatches.map((m) => m[1]).filter(Boolean);
    const votes = names.map((n) => classifyName(n)).filter(Boolean);
    return majority(votes);
}
function detectImportStyle(content) {
    const relativeImports = (content.match(/from\s+['"][./]/g) ?? []).length;
    const aliasImports = (content.match(/from\s+['"][@$#~]/g) ?? []).length;
    if (relativeImports === 0 && aliasImports === 0) {
        return 'unknown';
    }
    if (relativeImports > 0 && aliasImports > 0) {
        return 'mixed';
    }
    return aliasImports > relativeImports ? 'alias' : 'relative';
}
function detectErrorHandling(content) {
    const throwCount = (content.match(/throw new \w*Error/g) ?? []).length;
    const resultCount = (content.match(/Result<|Either<|\.ok\(|\.err\(/g) ?? []).length;
    const returnErrCount = (content.match(/return \[(?:null|undefined|false),|return \[.*error/gi) ?? []).length;
    const total = throwCount + resultCount + returnErrCount;
    if (total === 0) {
        return 'unknown';
    }
    const dominantThreshold = total * 0.6;
    if (throwCount >= dominantThreshold) {
        return 'exceptions';
    }
    if (resultCount >= dominantThreshold) {
        return 'result-type';
    }
    if (returnErrCount >= dominantThreshold) {
        return 'error-returns';
    }
    return 'mixed';
}
async function detectTestLocation(projectPath) {
    try {
        const [separateFiles, colocatedFiles] = await Promise.all([
            glob('tests/**/*.{test,spec}.{ts,js}', { cwd: projectPath }).catch(() => []),
            glob('src/**/*.{test,spec}.{ts,js}', { cwd: projectPath }).catch(() => []),
        ]);
        if (separateFiles.length === 0 && colocatedFiles.length === 0) {
            return 'unknown';
        }
        if (separateFiles.length >= colocatedFiles.length) {
            return 'separate';
        }
        return 'colocated';
    }
    catch {
        return 'unknown';
    }
}
export async function detectConventions(projectPath) {
    const sampleFiles = await sampleSourceFiles(projectPath);
    const contents = await Promise.all(sampleFiles.map(readFirstLines));
    const combined = contents.join('\n');
    const [fileNaming, testLocation] = await Promise.all([
        detectFileNaming(projectPath),
        detectTestLocation(projectPath),
    ]);
    const functionNaming = detectFunctionNaming(combined);
    const importStyle = detectImportStyle(combined);
    const errorHandling = detectErrorHandling(combined);
    return { fileNaming, functionNaming, testLocation, importStyle, errorHandling };
}
//# sourceMappingURL=convention-detector.js.map