"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeCodeHealth = computeCodeHealth;
exports.formatCodeHealth = formatCodeHealth;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
function computeCodeHealth(projectDir, project) {
    const suggestions = [];
    // Scan files
    const files = scanCodeFiles(projectDir);
    const metrics = computeMetrics(files, projectDir);
    // Complexity analysis (simplified: line count as proxy)
    const complexity = computeComplexityScore(files);
    // Duplication detection (simplified: similar file sizes)
    const duplication = computeDuplicationScore(files);
    // Test coverage (test file ratio)
    const testCoverage = computeTestCoverage(files);
    // Documentation (README, docs)
    const documentation = computeDocumentationScore(projectDir);
    // Error handling (try/catch usage)
    const errorHandling = computeErrorHandlingScore(files);
    // Modularity (avg file size, number of modules)
    const modularity = computeModularityScore(files);
    // Generate suggestions
    if (metrics.testRatio < 0.2) {
        suggestions.push('Add more test files — current test ratio is low');
    }
    if (metrics.highComplexityFiles > 3) {
        suggestions.push('Refactor high-complexity files');
    }
    if (metrics.avgFileSize > 500) {
        suggestions.push('Consider splitting large files');
    }
    if (documentation < 50) {
        suggestions.push('Add README and documentation');
    }
    if (duplication < 60) {
        suggestions.push('Reduce code duplication');
    }
    if (errorHandling < 50) {
        suggestions.push('Improve error handling with try/catch');
    }
    // Overall score
    const overallScore = Math.round(complexity * 0.2 +
        duplication * 0.15 +
        testCoverage * 0.25 +
        documentation * 0.1 +
        errorHandling * 0.15 +
        modularity * 0.15);
    const grade = scoreToGrade(overallScore);
    // Top files by complexity
    const topFiles = files
        .sort((a, b) => b.lines - a.lines)
        .slice(0, 20)
        .map(f => ({
        path: path.relative(projectDir, f.path),
        lines: f.lines,
        complexity: f.complexity,
        health: f.lines > 500 ? 'critical' : f.lines > 200 ? 'warning' : 'good',
        issues: f.lines > 500 ? ['File too large'] : [],
    }));
    return {
        project,
        overallScore,
        grade,
        dimensions: { complexity, duplication, testCoverage, documentation, errorHandling, modularity },
        files: topFiles,
        suggestions,
        metrics,
        computedAt: new Date().toISOString(),
    };
}
function scanCodeFiles(dir) {
    const files = [];
    const extensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.rs', '.java']);
    const ignoreDirs = new Set(['node_modules', '.git', 'dist', 'build', '.cell', '__tests__', '__mocks__']);
    function walk(currentDir) {
        try {
            const entries = fs.readdirSync(currentDir, { withFileTypes: true });
            for (const entry of entries) {
                if (ignoreDirs.has(entry.name))
                    continue;
                const fullPath = path.join(currentDir, entry.name);
                if (entry.isDirectory()) {
                    walk(fullPath);
                }
                else if (extensions.has(path.extname(entry.name).toLowerCase())) {
                    try {
                        const content = fs.readFileSync(fullPath, 'utf-8');
                        const lines = content.split('\n').length;
                        const complexity = estimateComplexity(content);
                        const isTest = entry.name.includes('.test.') || entry.name.includes('.spec.') || fullPath.includes('__tests__');
                        const isDoc = entry.name.endsWith('.md') || entry.name.endsWith('.txt');
                        const isConfig = entry.name.endsWith('.json') || entry.name.endsWith('.yaml') || entry.name.endsWith('.yml');
                        files.push({ path: fullPath, lines, complexity, isTest, isDoc, isConfig });
                    }
                    catch { }
                }
            }
        }
        catch { }
    }
    walk(dir);
    return files;
}
function estimateComplexity(content) {
    // Simple complexity heuristic: count control flow statements
    let complexity = 1;
    const lines = content.split('\n');
    for (const line of lines) {
        const trimmed = line.trim();
        if (trimmed.startsWith('//') || trimmed.startsWith('*'))
            continue;
        if (/\b(if|else if|else)\b/.test(trimmed))
            complexity++;
        if (/\b(for|while|do)\b/.test(trimmed))
            complexity++;
        if (/\b(switch|case)\b/.test(trimmed))
            complexity++;
        if (/\b(try|catch|finally)\b/.test(trimmed))
            complexity++;
        if (/\b(function|class|=>)\b/.test(trimmed))
            complexity++;
    }
    return complexity;
}
function computeMetrics(files, projectDir) {
    const codeFiles = files.filter(f => !f.isDoc && !f.isConfig);
    const testFiles = files.filter(f => f.isTest);
    const docFiles = files.filter(f => f.isDoc);
    const configFiles = files.filter(f => f.isConfig);
    const totalLines = codeFiles.reduce((s, f) => s + f.lines, 0);
    const avgFileSize = codeFiles.length > 0 ? Math.round(totalLines / codeFiles.length) : 0;
    const largest = codeFiles.reduce((max, f) => f.lines > max.lines ? f : max, { path: '', lines: 0 });
    const testRatio = codeFiles.length > 0 ? Math.round(testFiles.length / codeFiles.length * 100) : 0;
    const highComplexityFiles = codeFiles.filter(f => f.complexity > 50).length;
    const avgComplexity = codeFiles.length > 0
        ? Math.round(codeFiles.reduce((s, f) => s + f.complexity, 0) / codeFiles.length)
        : 0;
    return {
        totalFiles: codeFiles.length,
        totalLines,
        avgFileSize,
        largestFile: path.relative(projectDir, largest.path),
        largestFileSize: largest.lines,
        testFiles: testFiles.length,
        testRatio,
        docFiles: docFiles.length,
        configFiles: configFiles.length,
        avgComplexity,
        highComplexityFiles,
    };
}
function computeComplexityScore(files) {
    const codeFiles = files.filter(f => !f.isDoc && !f.isConfig);
    if (codeFiles.length === 0)
        return 50;
    const avgComplexity = codeFiles.reduce((s, f) => s + f.complexity, 0) / codeFiles.length;
    // Lower complexity = higher score
    if (avgComplexity < 10)
        return 95;
    if (avgComplexity < 20)
        return 85;
    if (avgComplexity < 30)
        return 75;
    if (avgComplexity < 50)
        return 60;
    if (avgComplexity < 80)
        return 45;
    return 30;
}
function computeDuplicationScore(files) {
    // Simple: check if many files have same line count (proxy for copy-paste)
    const codeFiles = files.filter(f => !f.isDoc && !f.isConfig && f.lines > 10);
    if (codeFiles.length === 0)
        return 80;
    const lineCounts = codeFiles.map(f => f.lines);
    const unique = new Set(lineCounts);
    const ratio = unique.size / lineCounts.length;
    return Math.round(ratio * 100);
}
function computeTestCoverage(files) {
    const codeFiles = files.filter(f => !f.isDoc && !f.isConfig);
    const testFiles = files.filter(f => f.isTest);
    if (codeFiles.length === 0)
        return 50;
    const ratio = testFiles.length / codeFiles.length;
    if (ratio > 0.5)
        return 95;
    if (ratio > 0.3)
        return 85;
    if (ratio > 0.2)
        return 70;
    if (ratio > 0.1)
        return 55;
    if (ratio > 0.05)
        return 40;
    return 25;
}
function computeDocumentationScore(projectDir) {
    let score = 0;
    const readme = path.join(projectDir, 'README.md');
    if (fs.existsSync(readme))
        score += 40;
    const docsDir = path.join(projectDir, 'docs');
    if (fs.existsSync(docsDir))
        score += 30;
    const changelog = path.join(projectDir, 'CHANGELOG.md');
    if (fs.existsSync(changelog))
        score += 15;
    const license = path.join(projectDir, 'LICENSE');
    if (fs.existsSync(license))
        score += 15;
    return Math.min(100, score);
}
function computeErrorHandlingScore(files) {
    let totalFiles = 0;
    let filesWithTry = 0;
    for (const f of files) {
        if (f.isTest || f.isDoc || f.isConfig)
            continue;
        totalFiles++;
        try {
            const content = fs.readFileSync(f.path, 'utf-8');
            if (/\b(try|catch)\b/.test(content))
                filesWithTry++;
        }
        catch { }
    }
    if (totalFiles === 0)
        return 50;
    const ratio = filesWithTry / totalFiles;
    if (ratio > 0.5)
        return 90;
    if (ratio > 0.3)
        return 75;
    if (ratio > 0.15)
        return 60;
    if (ratio > 0.05)
        return 45;
    return 30;
}
function computeModularityScore(files) {
    const codeFiles = files.filter(f => !f.isDoc && !f.isConfig);
    if (codeFiles.length === 0)
        return 50;
    const avgSize = codeFiles.reduce((s, f) => s + f.lines, 0) / codeFiles.length;
    // Smaller avg size = better modularity
    if (avgSize < 100)
        return 95;
    if (avgSize < 200)
        return 85;
    if (avgSize < 300)
        return 75;
    if (avgSize < 500)
        return 60;
    if (avgSize < 800)
        return 45;
    return 30;
}
function scoreToGrade(score) {
    if (score >= 95)
        return 'A+';
    if (score >= 90)
        return 'A';
    if (score >= 85)
        return 'B+';
    if (score >= 75)
        return 'B';
    if (score >= 70)
        return 'C+';
    if (score >= 60)
        return 'C';
    if (score >= 40)
        return 'D';
    return 'F';
}
function formatCodeHealth(health) {
    const lines = [];
    lines.push(`## Code Health — ${health.project}`);
    lines.push(`**Score: ${health.overallScore}/100 (${health.grade})**\n`);
    lines.push(`### Dimensions`);
    lines.push(`| Dimension | Score |`);
    lines.push(`|-----------|-------|`);
    lines.push(`| Complexity | ${health.dimensions.complexity} |`);
    lines.push(`| Duplication | ${health.dimensions.duplication} |`);
    lines.push(`| Test Coverage | ${health.dimensions.testCoverage} |`);
    lines.push(`| Documentation | ${health.dimensions.documentation} |`);
    lines.push(`| Error Handling | ${health.dimensions.errorHandling} |`);
    lines.push(`| Modularity | ${health.dimensions.modularity} |`);
    lines.push('');
    lines.push(`### Metrics`);
    lines.push(`| Metric | Value |`);
    lines.push(`|--------|-------|`);
    lines.push(`| Total files | ${health.metrics.totalFiles} |`);
    lines.push(`| Total lines | ${health.metrics.totalLines} |`);
    lines.push(`| Avg file size | ${health.metrics.avgFileSize} lines |`);
    lines.push(`| Largest file | ${health.metrics.largestFile} (${health.metrics.largestFileSize} lines) |`);
    lines.push(`| Test files | ${health.metrics.testFiles} (${health.metrics.testRatio}% ratio) |`);
    lines.push(`| Doc files | ${health.metrics.docFiles} |`);
    lines.push(`| Avg complexity | ${health.metrics.avgComplexity} |`);
    lines.push(`| High complexity | ${health.metrics.highComplexityFiles} files |`);
    if (health.suggestions.length > 0) {
        lines.push('');
        lines.push(`### Suggestions`);
        for (const s of health.suggestions)
            lines.push(`- ${s}`);
    }
    return lines.join('\n');
}
//# sourceMappingURL=code-health.js.map