import { promises as fs } from 'fs';
import path from 'path';
import crypto from 'crypto';
export class CodeAnalyzer {
    knownPatterns;
    constructor() {
        this.knownPatterns = this.initializePatterns();
    }
    async findCodeFiles(directory, excludePatterns = []) {
        const files = [];
        async function walk(dir) {
            const entries = await fs.readdir(dir, { withFileTypes: true });
            for (const entry of entries) {
                const fullPath = path.join(dir, entry.name);
                const relativePath = path.relative(directory, fullPath);
                // Check if should exclude
                if (excludePatterns.some(pattern => {
                    // Simple glob matching
                    const regex = pattern
                        .replace(/\*\*/g, '.*')
                        .replace(/\*/g, '[^/]*')
                        .replace(/\?/g, '.');
                    return new RegExp(`^${regex}$`).test(relativePath);
                })) {
                    continue;
                }
                if (entry.isDirectory()) {
                    await walk(fullPath);
                }
                else if (entry.isFile() && isCodeFile(entry.name)) {
                    files.push(fullPath);
                }
            }
        }
        function isCodeFile(name) {
            const codeExtensions = ['.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.cpp', '.c', '.h', '.cs', '.rb', '.go', '.rust', '.swift', '.php'];
            return codeExtensions.some(ext => name.endsWith(ext));
        }
        await walk(directory);
        return files;
    }
    generateSuggestions(analysis) {
        const suggestions = [];
        // Complexity suggestions
        if (analysis.metrics.complexity.average > 10) {
            suggestions.push({
                title: 'Reduce complexity',
                description: 'Consider breaking down complex functions into smaller, more manageable pieces',
                priority: 'high',
            });
        }
        // Maintainability suggestions
        if (analysis.metrics.maintainability.average < 70) {
            suggestions.push({
                title: 'Improve maintainability',
                description: 'Add documentation, reduce complexity, and improve code organization',
                priority: 'medium',
            });
        }
        // Duplication suggestions
        if (analysis.metrics.duplication.percentage > 5) {
            suggestions.push({
                title: 'Reduce code duplication',
                description: 'Extract common code into reusable functions or modules',
                priority: 'medium',
            });
        }
        return suggestions;
    }
    generateRefactoringIdeas(analysis) {
        const ideas = [];
        // Check for long functions
        const longFunctions = analysis.metrics.complexity.functions.filter(f => f.lines > 50);
        if (longFunctions.length > 0) {
            ideas.push({
                title: 'Split long functions',
                description: `${longFunctions.length} functions exceed 50 lines. Consider splitting them`,
                priority: 'medium',
            });
        }
        // Check for high parameter count
        const highParamFunctions = analysis.metrics.complexity.functions.filter(f => f.parameters > 5);
        if (highParamFunctions.length > 0) {
            ideas.push({
                title: 'Reduce parameter count',
                description: `${highParamFunctions.length} functions have more than 5 parameters. Consider using objects or builder patterns`,
                priority: 'low',
            });
        }
        return ideas;
    }
    async analyzeFile(filePath) {
        const content = await fs.readFile(filePath, 'utf-8');
        const stats = await fs.stat(filePath);
        const language = this.detectLanguage(filePath);
        const metrics = await this.calculateMetrics(content, language);
        const issues = await this.detectIssues(content, filePath, language);
        return {
            path: filePath,
            metrics,
            issues,
            size: stats.size,
            language,
            lastModified: stats.mtime.toISOString(),
        };
    }
    async calculateMetrics(content, language) {
        const complexity = this.calculateComplexity(content, language);
        const maintainability = this.calculateMaintainability(content, complexity);
        const duplication = this.detectDuplication(content);
        const quality = await this.assessQuality(content, complexity, maintainability, duplication);
        return {
            complexity,
            maintainability,
            duplication,
            quality,
        };
    }
    calculateComplexity(content, language) {
        const functions = this.extractFunctions(content, language);
        const cyclomaticComplexity = this.calculateCyclomaticComplexity(content);
        const cognitiveComplexity = this.calculateCognitiveComplexity(content);
        const halstead = this.calculateHalsteadMetrics(content);
        const average = functions.length > 0
            ? functions.reduce((sum, f) => sum + f.complexity, 0) / functions.length
            : cyclomaticComplexity;
        const max = functions.length > 0
            ? Math.max(...functions.map(f => f.complexity))
            : cyclomaticComplexity;
        return {
            cyclomatic: cyclomaticComplexity,
            cognitive: cognitiveComplexity,
            halstead,
            functions,
            average,
            max,
            total: cyclomaticComplexity,
        };
    }
    calculateCyclomaticComplexity(content) {
        // Count decision points
        const patterns = [
            /\bif\b/g,
            /\belse\s+if\b/g,
            /\belse\b/g,
            /\bfor\b/g,
            /\bwhile\b/g,
            /\bdo\b/g,
            /\bswitch\b/g,
            /\bcase\b/g,
            /\bcatch\b/g,
            /\?\s*[^:]+\s*:/g, // ternary
            /&&/g,
            /\|\|/g,
            /\?\?/g, // nullish coalescing
        ];
        let complexity = 1; // Base complexity
        patterns.forEach(pattern => {
            const matches = content.match(pattern);
            if (matches) {
                complexity += matches.length;
            }
        });
        // Adjust for certain patterns
        const elseIfMatches = content.match(/\belse\s+if\b/g);
        if (elseIfMatches) {
            // Don't double count else if
            complexity -= elseIfMatches.length;
        }
        return complexity;
    }
    calculateCognitiveComplexity(content) {
        let complexity = 0;
        let nestingLevel = 0;
        const lines = content.split('\n');
        const incrementPatterns = [
            /\bif\b/,
            /\belse\s+if\b/,
            /\belse\b/,
            /\bfor\b/,
            /\bwhile\b/,
            /\bdo\b/,
            /\bcatch\b/,
        ];
        const nestingPatterns = [
            /\bif\b/,
            /\bfor\b/,
            /\bwhile\b/,
            /\bdo\b/,
        ];
        lines.forEach(line => {
            const trimmed = line.trim();
            // Check for nesting increase
            nestingPatterns.forEach(pattern => {
                if (pattern.test(trimmed) && trimmed.includes('{')) {
                    nestingLevel++;
                }
            });
            // Check for complexity increment
            incrementPatterns.forEach(pattern => {
                if (pattern.test(trimmed)) {
                    complexity += 1 + nestingLevel;
                }
            });
            // Check for nesting decrease
            if (trimmed.includes('}')) {
                nestingLevel = Math.max(0, nestingLevel - 1);
            }
        });
        return complexity;
    }
    calculateHalsteadMetrics(content) {
        // Simplified Halstead metrics calculation
        const operators = new Set();
        const operands = new Set();
        let totalOperators = 0;
        let totalOperands = 0;
        // Extract operators
        const operatorPatterns = [
            /[+\-*/%=<>!&|^~]/g,
            /\b(if|else|for|while|do|switch|case|break|continue|return|throw|try|catch|finally)\b/g,
        ];
        operatorPatterns.forEach(pattern => {
            const matches = content.match(pattern);
            if (matches) {
                matches.forEach(match => {
                    operators.add(match);
                    totalOperators++;
                });
            }
        });
        // Extract operands (simplified - identifiers and literals)
        const operandPattern = /\b[a-zA-Z_]\w*\b|\b\d+\b|"[^"]*"|'[^']*'/g;
        const operandMatches = content.match(operandPattern);
        if (operandMatches) {
            operandMatches.forEach(match => {
                if (!operators.has(match)) {
                    operands.add(match);
                    totalOperands++;
                }
            });
        }
        const n1 = operators.size; // unique operators
        const n2 = operands.size; // unique operands
        const N1 = totalOperators; // total operators
        const N2 = totalOperands; // total operands
        const vocabulary = n1 + n2;
        const length = N1 + N2;
        const volume = length * Math.log2(vocabulary || 1);
        const difficulty = (n1 / 2) * (N2 / (n2 || 1));
        const effort = difficulty * volume;
        return {
            difficulty: Math.round(difficulty * 100) / 100,
            volume: Math.round(volume * 100) / 100,
            effort: Math.round(effort * 100) / 100,
        };
    }
    extractFunctions(content, language) {
        const functions = [];
        // Patterns for different languages
        const patterns = {
            javascript: /(?:function\s+(\w+)|const\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>|(\w+)\s*:\s*(?:async\s*)?\([^)]*\)\s*=>)/g,
            typescript: /(?:function\s+(\w+)|const\s+(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>|(\w+)\s*:\s*(?:async\s*)?\([^)]*\)\s*=>|(?:public|private|protected)\s+(?:async\s+)?(\w+)\s*\([^)]*\))/g,
            python: /def\s+(\w+)\s*\([^)]*\):/g,
            java: /(?:public|private|protected)?\s*(?:static)?\s*(?:\w+)\s+(\w+)\s*\([^)]*\)\s*{/g,
        };
        const pattern = patterns[language] || patterns.javascript;
        const lines = content.split('\n');
        let match;
        while ((match = pattern.exec(content)) !== null) {
            const functionName = match[1] || match[2] || match[3] || match[4] || 'anonymous';
            const startIndex = match.index;
            const lineNumber = content.substring(0, startIndex).split('\n').length;
            // Extract function body (simplified)
            const functionStart = startIndex;
            const functionBody = this.extractFunctionBody(content, functionStart, language);
            const functionLines = functionBody.split('\n').length;
            // Calculate function-specific complexity
            const functionComplexity = this.calculateCyclomaticComplexity(functionBody);
            // Count parameters (simplified)
            const paramsMatch = match[0].match(/\(([^)]*)\)/);
            const parameters = paramsMatch && paramsMatch[1].trim()
                ? paramsMatch[1].split(',').length
                : 0;
            functions.push({
                name: functionName,
                complexity: functionComplexity,
                lines: functionLines,
                parameters,
                location: {
                    file: '',
                    line: lineNumber,
                    column: 1,
                },
            });
        }
        return functions;
    }
    extractFunctionBody(content, startIndex, language) {
        // Simplified function body extraction
        if (language === 'python') {
            // Python uses indentation
            const lines = content.substring(startIndex).split('\n');
            const functionLines = [lines[0]];
            const baseIndent = lines[0].match(/^\s*/)?.[0].length || 0;
            for (let i = 1; i < lines.length; i++) {
                const currentIndent = lines[i].match(/^\s*/)?.[0].length || 0;
                if (currentIndent > baseIndent || lines[i].trim() === '') {
                    functionLines.push(lines[i]);
                }
                else {
                    break;
                }
            }
            return functionLines.join('\n');
        }
        else {
            // Brace-based languages
            let braceCount = 0;
            let inFunction = false;
            let functionEnd = startIndex;
            for (let i = startIndex; i < content.length; i++) {
                if (content[i] === '{') {
                    braceCount++;
                    inFunction = true;
                }
                else if (content[i] === '}') {
                    braceCount--;
                    if (inFunction && braceCount === 0) {
                        functionEnd = i + 1;
                        break;
                    }
                }
            }
            return content.substring(startIndex, functionEnd);
        }
    }
    calculateMaintainability(content, complexity) {
        const lines = content.split('\n');
        const totalLines = lines.length;
        const codeLines = lines.filter(line => line.trim() && !line.trim().startsWith('//')).length;
        const commentLines = lines.filter(line => line.trim().startsWith('//') || line.trim().startsWith('/*')).length;
        const commentRatio = commentLines / (codeLines || 1);
        // Simplified maintainability index calculation
        // MI = 171 - 5.2 * ln(Halstead Volume) - 0.23 * (Cyclomatic Complexity) - 16.2 * ln(Lines of Code)
        const volume = complexity.halstead.volume || 1;
        const cyclomatic = complexity.cyclomatic || 1;
        let maintainabilityIndex = 171
            - 5.2 * Math.log(volume)
            - 0.23 * cyclomatic
            - 16.2 * Math.log(codeLines || 1);
        // Normalize to 0-100
        maintainabilityIndex = Math.max(0, Math.min(100, maintainabilityIndex));
        // Determine rating
        let rating;
        if (maintainabilityIndex >= 80)
            rating = 'A';
        else if (maintainabilityIndex >= 60)
            rating = 'B';
        else if (maintainabilityIndex >= 40)
            rating = 'C';
        else if (maintainabilityIndex >= 20)
            rating = 'D';
        else
            rating = 'F';
        return {
            index: Math.round(maintainabilityIndex * 100) / 100,
            rating,
            factors: {
                complexity: complexity.cyclomatic,
                lineCount: codeLines,
                commentRatio: Math.round(commentRatio * 100) / 100,
            },
            average: Math.round(maintainabilityIndex * 100) / 100,
            min: Math.round(maintainabilityIndex * 100) / 100,
            distribution: {},
        };
    }
    detectDuplication(content) {
        const lines = content.split('\n');
        const totalLines = lines.length;
        const blockSize = 6; // Minimum duplicate block size
        const hashes = new Map();
        const duplicateBlocks = [];
        // Create hashes for each block of lines
        for (let i = 0; i <= lines.length - blockSize; i++) {
            const block = lines.slice(i, i + blockSize).join('\n');
            const hash = this.hashBlock(block);
            if (!hashes.has(hash)) {
                hashes.set(hash, []);
            }
            hashes.get(hash).push(i);
        }
        // Find duplicate blocks
        let duplicatedLines = 0;
        const processedLines = new Set();
        hashes.forEach((locations, hash) => {
            if (locations.length > 1) {
                const block = {
                    locations: locations.map(line => ({
                        file: '',
                        line: line + 1,
                        column: 1,
                        endLine: line + blockSize,
                    })),
                    lines: blockSize,
                    tokens: blockSize * 10, // Approximation
                    hash,
                };
                duplicateBlocks.push(block);
                // Count duplicated lines (avoid double counting)
                locations.forEach(loc => {
                    for (let i = loc; i < loc + blockSize; i++) {
                        if (!processedLines.has(i)) {
                            processedLines.add(i);
                            duplicatedLines++;
                        }
                    }
                });
            }
        });
        const percentage = (duplicatedLines / totalLines) * 100;
        return {
            percentage: Math.round(percentage * 100) / 100,
            duplicateBlocks,
            totalLines,
            duplicatedLines,
            blocks: duplicateBlocks.length,
        };
    }
    hashBlock(block) {
        // Normalize whitespace and create hash
        const normalized = block
            .split('\n')
            .map(line => line.trim())
            .filter(line => line && !line.startsWith('//'))
            .join('\n');
        return crypto.createHash('md5').update(normalized).digest('hex');
    }
    async assessQuality(content, complexity, maintainability, duplication) {
        const issues = await this.detectIssues(content, '', this.detectLanguage(''));
        // Calculate quality score
        let score = 100;
        // Deduct for complexity
        if (complexity.cyclomatic > 10)
            score -= 10;
        if (complexity.cyclomatic > 20)
            score -= 10;
        // Deduct for maintainability
        if (maintainability.rating === 'B')
            score -= 5;
        if (maintainability.rating === 'C')
            score -= 10;
        if (maintainability.rating === 'D')
            score -= 20;
        if (maintainability.rating === 'F')
            score -= 30;
        // Deduct for duplication
        if (duplication.percentage > 5)
            score -= 5;
        if (duplication.percentage > 10)
            score -= 10;
        if (duplication.percentage > 20)
            score -= 20;
        // Deduct for issues
        issues.forEach(issue => {
            if (issue.severity === 'critical')
                score -= 10;
            else if (issue.severity === 'high')
                score -= 5;
            else if (issue.severity === 'medium')
                score -= 2;
            else if (issue.severity === 'low')
                score -= 1;
        });
        score = Math.max(0, score);
        // Determine grade
        let grade;
        if (score >= 90)
            grade = 'A';
        else if (score >= 80)
            grade = 'B';
        else if (score >= 70)
            grade = 'C';
        else if (score >= 60)
            grade = 'D';
        else
            grade = 'F';
        const issuesSummary = {
            total: issues.length,
            high: issues.filter(i => i.severity === 'high').length,
            medium: issues.filter(i => i.severity === 'medium').length,
            low: issues.filter(i => i.severity === 'low').length,
        };
        return {
            issues: issuesSummary,
            codeSmells: issues.filter(i => i.category === 'maintainability').length,
            technicalDebt: Math.round(issues.length * 0.5),
            score,
            grade,
        };
    }
    async detectIssues(content, filePath, language) {
        const issues = [];
        const lines = content.split('\n');
        // Security issues
        this.detectSecurityIssues(lines, issues);
        // Performance issues
        this.detectPerformanceIssues(lines, issues);
        // Code quality issues
        this.detectQualityIssues(lines, issues);
        // Style issues
        this.detectStyleIssues(lines, issues);
        return issues;
    }
    detectSecurityIssues(lines, issues) {
        const securityPatterns = [
            {
                pattern: /eval\s*\(/,
                message: 'Avoid using eval() as it can execute arbitrary code',
                severity: 'critical',
                rule: 'no-eval',
            },
            {
                pattern: /innerHTML\s*=/,
                message: 'Direct innerHTML assignment can lead to XSS vulnerabilities',
                severity: 'high',
                rule: 'no-inner-html',
            },
            {
                pattern: /password.*=.*["'][^"']+["']/i,
                message: 'Hardcoded password detected',
                severity: 'critical',
                rule: 'no-hardcoded-secrets',
            },
            {
                pattern: /api[_-]?key.*=.*["'][^"']+["']/i,
                message: 'Hardcoded API key detected',
                severity: 'critical',
                rule: 'no-hardcoded-secrets',
            },
        ];
        lines.forEach((line, index) => {
            securityPatterns.forEach(({ pattern, message, severity, rule }) => {
                if (pattern.test(line)) {
                    issues.push({
                        type: 'error',
                        severity,
                        rule,
                        message,
                        location: {
                            file: '',
                            line: index + 1,
                            column: line.search(pattern) + 1,
                        },
                        fixable: false,
                        category: 'security',
                    });
                }
            });
        });
    }
    detectPerformanceIssues(lines, issues) {
        const performancePatterns = [
            {
                pattern: /\.forEach\s*\([^)]*\)\s*{[^}]*\.push\s*\(/,
                message: 'Consider using map() instead of forEach() with push()',
                severity: 'medium',
                rule: 'prefer-map',
            },
            {
                pattern: /for\s*\([^)]*in\s+/,
                message: 'for...in loop can be slow for arrays, consider for...of or traditional for loop',
                severity: 'low',
                rule: 'no-for-in',
            },
        ];
        lines.forEach((line, index) => {
            performancePatterns.forEach(({ pattern, message, severity, rule }) => {
                if (pattern.test(line)) {
                    issues.push({
                        type: 'warning',
                        severity,
                        rule,
                        message,
                        location: {
                            file: '',
                            line: index + 1,
                            column: 1,
                        },
                        fixable: true,
                        category: 'performance',
                    });
                }
            });
        });
    }
    detectQualityIssues(lines, issues) {
        lines.forEach((line, index) => {
            // Long lines
            if (line.length > 120) {
                issues.push({
                    type: 'warning',
                    severity: 'low',
                    rule: 'max-line-length',
                    message: `Line exceeds maximum length of 120 characters (${line.length})`,
                    location: {
                        file: '',
                        line: index + 1,
                        column: 121,
                    },
                    fixable: true,
                    category: 'style',
                });
            }
            // TODO comments
            if (/\/\/\s*TODO|\/\*\s*TODO/.test(line)) {
                issues.push({
                    type: 'info',
                    severity: 'low',
                    rule: 'no-todo',
                    message: 'TODO comment found',
                    location: {
                        file: '',
                        line: index + 1,
                        column: line.search(/TODO/) + 1,
                    },
                    fixable: false,
                    category: 'maintainability',
                });
            }
            // Console.log statements
            if (/console\.(log|error|warn|info)/.test(line)) {
                issues.push({
                    type: 'warning',
                    severity: 'medium',
                    rule: 'no-console',
                    message: 'Remove console statements before production',
                    location: {
                        file: '',
                        line: index + 1,
                        column: line.search(/console\./) + 1,
                    },
                    fixable: true,
                    category: 'reliability',
                });
            }
        });
    }
    detectStyleIssues(lines, issues) {
        lines.forEach((line, index) => {
            // Trailing whitespace
            if (/\s+$/.test(line)) {
                issues.push({
                    type: 'style',
                    severity: 'low',
                    rule: 'no-trailing-spaces',
                    message: 'Trailing whitespace',
                    location: {
                        file: '',
                        line: index + 1,
                        column: line.search(/\s+$/) + 1,
                    },
                    fixable: true,
                    category: 'style',
                });
            }
            // Mixed tabs and spaces
            if (/^\t+ /.test(line) || /^ +\t/.test(line)) {
                issues.push({
                    type: 'style',
                    severity: 'low',
                    rule: 'no-mixed-spaces-and-tabs',
                    message: 'Mixed spaces and tabs',
                    location: {
                        file: '',
                        line: index + 1,
                        column: 1,
                    },
                    fixable: true,
                    category: 'style',
                });
            }
        });
    }
    detectLanguage(filePath) {
        const ext = path.extname(filePath).toLowerCase();
        const languageMap = {
            '.js': 'javascript',
            '.jsx': 'javascript',
            '.ts': 'typescript',
            '.tsx': 'typescript',
            '.py': 'python',
            '.java': 'java',
            '.c': 'c',
            '.cpp': 'cpp',
            '.cs': 'csharp',
            '.go': 'go',
            '.rb': 'ruby',
            '.php': 'php',
            '.swift': 'swift',
            '.kt': 'kotlin',
            '.rs': 'rust',
        };
        return languageMap[ext] || 'unknown';
    }
    initializePatterns() {
        const patterns = new Map();
        // Add common patterns for various languages
        patterns.set('function-declaration-js', /function\s+\w+\s*\([^)]*\)\s*{/g);
        patterns.set('arrow-function-js', /\w+\s*=\s*(?:async\s*)?\([^)]*\)\s*=>/g);
        patterns.set('class-declaration-js', /class\s+\w+(?:\s+extends\s+\w+)?\s*{/g);
        return patterns;
    }
    async analyzeDirectory(dirPath, options = {}) {
        const files = await this.getFilesRecursively(dirPath, options.excludePatterns);
        const fileAnalyses = [];
        for (const file of files) {
            try {
                const analysis = await this.analyzeFile(file);
                fileAnalyses.push(analysis);
            }
            catch (error) {
                console.error(`Error analyzing ${file}:`, error);
            }
        }
        const summary = this.generateSummary(fileAnalyses);
        const recommendations = this.generateRecommendations(summary);
        return {
            id: crypto.randomUUID(),
            timestamp: new Date().toISOString(),
            files: fileAnalyses,
            summary,
            recommendations,
        };
    }
    async getFilesRecursively(dirPath, excludePatterns = []) {
        const files = [];
        const entries = await fs.readdir(dirPath, { withFileTypes: true });
        for (const entry of entries) {
            const fullPath = path.join(dirPath, entry.name);
            // Check if should exclude
            if (excludePatterns.some(pattern => fullPath.includes(pattern))) {
                continue;
            }
            if (entry.isDirectory()) {
                // Skip common directories
                if (['node_modules', '.git', 'dist', 'build', 'coverage'].includes(entry.name)) {
                    continue;
                }
                const subFiles = await this.getFilesRecursively(fullPath, excludePatterns);
                files.push(...subFiles);
            }
            else if (entry.isFile()) {
                // Only include source files
                if (this.isSourceFile(entry.name)) {
                    files.push(fullPath);
                }
            }
        }
        return files;
    }
    isSourceFile(fileName) {
        const sourceExtensions = [
            '.js', '.jsx', '.ts', '.tsx', '.py', '.java', '.c', '.cpp',
            '.cs', '.go', '.rb', '.php', '.swift', '.kt', '.rs'
        ];
        return sourceExtensions.some(ext => fileName.endsWith(ext));
    }
    generateSummary(files) {
        if (files.length === 0) {
            return {
                totalFiles: 0,
                totalLines: 0,
                averageComplexity: 0,
                averageMaintainability: 0,
                totalIssues: 0,
                criticalIssues: 0,
                duplicatePercentage: 0,
                overallScore: 0,
                overallGrade: 'F',
            };
        }
        const totalFiles = files.length;
        const totalLines = files.reduce((sum, f) => sum + f.metrics.duplication.totalLines, 0);
        const totalComplexity = files.reduce((sum, f) => sum + f.metrics.complexity.cyclomatic, 0);
        const totalMaintainability = files.reduce((sum, f) => sum + f.metrics.maintainability.index, 0);
        const totalIssues = files.reduce((sum, f) => sum + f.issues.length, 0);
        const criticalIssues = files.reduce((sum, f) => sum + f.issues.filter(i => i.severity === 'critical').length, 0);
        const totalDuplicatedLines = files.reduce((sum, f) => sum + f.metrics.duplication.duplicatedLines, 0);
        const overallScore = files.reduce((sum, f) => sum + f.metrics.quality.score, 0) / totalFiles;
        let overallGrade;
        if (overallScore >= 90)
            overallGrade = 'A';
        else if (overallScore >= 80)
            overallGrade = 'B';
        else if (overallScore >= 70)
            overallGrade = 'C';
        else if (overallScore >= 60)
            overallGrade = 'D';
        else
            overallGrade = 'F';
        return {
            totalFiles,
            totalLines,
            averageComplexity: Math.round((totalComplexity / totalFiles) * 100) / 100,
            averageMaintainability: Math.round((totalMaintainability / totalFiles) * 100) / 100,
            totalIssues,
            criticalIssues,
            duplicatePercentage: Math.round((totalDuplicatedLines / totalLines) * 100 * 100) / 100,
            overallScore: Math.round(overallScore * 100) / 100,
            overallGrade,
        };
    }
    generateRecommendations(summary) {
        const recommendations = [];
        if (summary.averageComplexity > 10) {
            recommendations.push('Consider refactoring complex functions to reduce cyclomatic complexity');
        }
        if (summary.averageMaintainability < 60) {
            recommendations.push('Improve code maintainability by reducing complexity and adding documentation');
        }
        if (summary.criticalIssues > 0) {
            recommendations.push(`Address ${summary.criticalIssues} critical security/quality issues immediately`);
        }
        if (summary.duplicatePercentage > 10) {
            recommendations.push('Reduce code duplication by extracting common functionality');
        }
        if (summary.overallGrade === 'D' || summary.overallGrade === 'F') {
            recommendations.push('Consider a comprehensive code quality improvement initiative');
        }
        if (recommendations.length === 0) {
            recommendations.push('Code quality is good! Consider adding more tests and documentation');
        }
        return recommendations;
    }
}
//# sourceMappingURL=analyzer.js.map