import { promises as fs } from 'fs';
import path from 'path';
import crypto from 'crypto';
import {
  CodeMetrics,
  ComplexityMetrics,
  MaintainabilityMetrics,
  DuplicationMetrics,
  QualityMetrics,
  CodeIssue,
  FunctionComplexity,
  DuplicateBlock,
  CodeLocation,
  FileAnalysis,
  AnalysisResult,
  AnalysisSummary,
  IssueCategory,
  Suggestion,
} from './types.js';

export class CodeAnalyzer {
  private knownPatterns: Map<string, RegExp>;

  constructor() {
    this.knownPatterns = this.initializePatterns();
  }

  async findCodeFiles(directory: string, excludePatterns: string[] = []): Promise<string[]> {
    const files: string[] = [];
    
    async function walk(dir: string) {
      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: string): boolean {
      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: FileAnalysis): Suggestion[] {
    const suggestions: Suggestion[] = [];
    
    // 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: FileAnalysis): Suggestion[] {
    const ideas: Suggestion[] = [];
    
    // 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: string): Promise<FileAnalysis> {
    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: string, language: string): Promise<CodeMetrics> {
    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,
    };
  }

  private calculateComplexity(content: string, language: string): ComplexityMetrics {
    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,
    };
  }

  private calculateCyclomaticComplexity(content: string): number {
    // 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;
  }

  private calculateCognitiveComplexity(content: string): number {
    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;
  }

  private calculateHalsteadMetrics(content: string) {
    // Simplified Halstead metrics calculation
    const operators = new Set<string>();
    const operands = new Set<string>();
    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,
    };
  }

  private extractFunctions(content: string, language: string): FunctionComplexity[] {
    const functions: FunctionComplexity[] = [];
    
    // Patterns for different languages
    const patterns: Record<string, RegExp> = {
      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;
  }

  private extractFunctionBody(content: string, startIndex: number, language: string): string {
    // 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);
    }
  }

  private calculateMaintainability(content: string, complexity: ComplexityMetrics): MaintainabilityMetrics {
    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: 'A' | 'B' | 'C' | 'D' | 'F';
    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: {},
    };
  }

  private detectDuplication(content: string): DuplicationMetrics {
    const lines = content.split('\n');
    const totalLines = lines.length;
    const blockSize = 6; // Minimum duplicate block size
    const hashes = new Map<string, number[]>();
    const duplicateBlocks: DuplicateBlock[] = [];
    
    // 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<number>();
    
    hashes.forEach((locations, hash) => {
      if (locations.length > 1) {
        const block: DuplicateBlock = {
          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,
    };
  }

  private hashBlock(block: string): string {
    // 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');
  }

  private async assessQuality(
    content: string,
    complexity: ComplexityMetrics,
    maintainability: MaintainabilityMetrics,
    duplication: DuplicationMetrics
  ): Promise<QualityMetrics> {
    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: 'A' | 'B' | 'C' | 'D' | 'F';
    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: string, filePath: string, language: string): Promise<CodeIssue[]> {
    const issues: CodeIssue[] = [];
    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;
  }

  private detectSecurityIssues(lines: string[], issues: CodeIssue[]) {
    const securityPatterns = [
      {
        pattern: /eval\s*\(/,
        message: 'Avoid using eval() as it can execute arbitrary code',
        severity: 'critical' as const,
        rule: 'no-eval',
      },
      {
        pattern: /innerHTML\s*=/,
        message: 'Direct innerHTML assignment can lead to XSS vulnerabilities',
        severity: 'high' as const,
        rule: 'no-inner-html',
      },
      {
        pattern: /password.*=.*["'][^"']+["']/i,
        message: 'Hardcoded password detected',
        severity: 'critical' as const,
        rule: 'no-hardcoded-secrets',
      },
      {
        pattern: /api[_-]?key.*=.*["'][^"']+["']/i,
        message: 'Hardcoded API key detected',
        severity: 'critical' as const,
        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',
          });
        }
      });
    });
  }

  private detectPerformanceIssues(lines: string[], issues: CodeIssue[]) {
    const performancePatterns = [
      {
        pattern: /\.forEach\s*\([^)]*\)\s*{[^}]*\.push\s*\(/,
        message: 'Consider using map() instead of forEach() with push()',
        severity: 'medium' as const,
        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' as const,
        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',
          });
        }
      });
    });
  }

  private detectQualityIssues(lines: string[], issues: CodeIssue[]) {
    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',
        });
      }
    });
  }

  private detectStyleIssues(lines: string[], issues: CodeIssue[]) {
    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: string): string {
    const ext = path.extname(filePath).toLowerCase();
    const languageMap: Record<string, string> = {
      '.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';
  }

  private initializePatterns(): Map<string, RegExp> {
    const patterns = new Map<string, RegExp>();
    
    // 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: string, options: { excludePatterns?: string[] } = {}): Promise<AnalysisResult> {
    const files = await this.getFilesRecursively(dirPath, options.excludePatterns);
    const fileAnalyses: FileAnalysis[] = [];
    
    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: string, excludePatterns: string[] = []): Promise<string[]> {
    const files: string[] = [];
    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;
  }

  private isSourceFile(fileName: string): boolean {
    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: FileAnalysis[]): AnalysisSummary {
    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: 'A' | 'B' | 'C' | 'D' | 'F';
    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: AnalysisSummary): string[] {
    const recommendations: string[] = [];
    
    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;
  }
}