// Planu — Simplicity metric engine (SPEC-482)
import { readFileSync } from 'node:fs';
/** Parse lines and count function argument lists to estimate param count. */
function avgParamCount(lines) {
    const counts = [];
    for (const line of lines) {
        const m = /(?:function\s+\w+|(?:const|let)\s+\w+\s*=\s*(?:async\s+)?\()\s*([^)]*)\)/.exec(line);
        if (m?.[1] !== undefined) {
            const params = m[1].trim();
            counts.push(params.length === 0 ? 0 : params.split(',').length);
        }
    }
    if (counts.length === 0) {
        return 0;
    }
    return counts.reduce((a, b) => a + b, 0) / counts.length;
}
/** Measure the maximum brace/block nesting depth. */
function maxNestingDepth(source) {
    let depth = 0;
    let max = 0;
    for (const ch of source) {
        if (ch === '{') {
            depth++;
            if (depth > max) {
                max = depth;
            }
        }
        else if (ch === '}') {
            depth = Math.max(0, depth - 1);
        }
    }
    return max;
}
/** Count nested ternary operators (? ... ? patterns). */
function ternaryChainCount(source) {
    const matches = source.match(/\?[^:]+\?/g);
    return matches !== null ? matches.length : 0;
}
/** Count regex literals as a heuristic for "clever" patterns. */
function regexCount(source) {
    // Match regex literals: /pattern/flags — avoid URLs by requiring non-/ char after opening slash
    const matches = source.match(/\/[^/\n]{2,}\/[gimsuy]*/g);
    return matches !== null ? matches.length : 0;
}
/** Compute average function body length in lines. */
function avgFunctionLength(source) {
    // Simple heuristic: split on `function` or arrow function declarations
    const fnRe = /(?:function\s+\w+|=>\s*\{)/g;
    const positions = [];
    let m;
    while ((m = fnRe.exec(source)) !== null) {
        positions.push(m.index);
    }
    if (positions.length === 0) {
        return 0;
    }
    const lines = source.split('\n');
    // Estimate average function length by distributing total lines / function count
    return lines.length / positions.length;
}
/** Convert a 0-100 score into an A-F grade. */
export function scoreToGrade(score) {
    if (score >= 90) {
        return 'A';
    }
    if (score >= 75) {
        return 'B';
    }
    if (score >= 60) {
        return 'C';
    }
    if (score >= 45) {
        return 'D';
    }
    return 'F';
}
/** Compute simplicity metrics for a single file. */
export function computeFileSimplicity(filePath) {
    let source;
    try {
        source = readFileSync(filePath, 'utf8');
    }
    catch {
        return null;
    }
    const lines = source.split('\n');
    const avgLen = avgFunctionLength(source);
    const maxDepth = maxNestingDepth(source);
    const ternaries = ternaryChainCount(source);
    const regexes = regexCount(source);
    const avgParams = avgParamCount(lines);
    // Scoring — each dimension penalizes from 100
    let score = 100;
    // Avg function length: >40 lines is bad
    if (avgLen > 40) {
        score -= Math.min(30, (avgLen - 40) * 0.75);
    }
    // Max nesting: >4 is bad
    if (maxDepth > 4) {
        score -= Math.min(25, (maxDepth - 4) * 5);
    }
    // Ternary chains
    if (ternaries > 2) {
        score -= Math.min(20, (ternaries - 2) * 5);
    }
    // Regex usage
    if (regexes > 3) {
        score -= Math.min(10, (regexes - 3) * 2);
    }
    // Avg params > 4
    if (avgParams > 4) {
        score -= Math.min(15, (avgParams - 4) * 3);
    }
    score = Math.max(0, Math.round(score));
    // Derive relative path from absolute path (keep last 3 segments for readability)
    const parts = filePath.replace(/\\/g, '/').split('/');
    const relFile = parts.slice(-3).join('/');
    return {
        file: relFile,
        avgFunctionLength: Math.round(avgLen * 10) / 10,
        maxNestingDepth: maxDepth,
        ternaryChainCount: ternaries,
        regexCount: regexes,
        avgParamCount: Math.round(avgParams * 10) / 10,
        score,
        grade: scoreToGrade(score),
    };
}
//# sourceMappingURL=simplicity.js.map