import { promises as fs } from 'fs';
import path from 'path';
import { CodeAnalysis, CodeMetrics, FunctionInfo, ComplexityReport } from './types.js';

export class CodeAnalyzer {
  async analyzeFile(filePath: string): Promise<CodeAnalysis> {
    const content = await fs.readFile(filePath, 'utf-8');
    const language = this.detectLanguage(filePath);
    
    const analysis: CodeAnalysis = {
      file: filePath,
      language,
      metrics: this.calculateMetrics(content),
      dependencies: this.extractDependencies(content, language),
      exports: this.extractExports(content, language),
      imports: this.extractImports(content, language),
      functions: this.extractFunctions(content, language),
      classes: this.extractClasses(content, language),
      complexity: this.analyzeComplexity(content, language),
    };
    
    return analysis;
  }

  private detectLanguage(filePath: string): string {
    const ext = path.extname(filePath).toLowerCase();
    const languageMap: Record<string, string> = {
      '.ts': 'typescript',
      '.tsx': 'typescript',
      '.js': 'javascript',
      '.jsx': 'javascript',
      '.py': 'python',
      '.rs': 'rust',
      '.go': 'go',
      '.java': 'java',
      '.cpp': 'cpp',
      '.c': 'c',
    };
    
    return languageMap[ext] || 'unknown';
  }

  private calculateMetrics(content: string): CodeMetrics {
    const lines = content.split('\n');
    let loc = 0;
    let comments = 0;
    let blanks = 0;
    
    for (const line of lines) {
      const trimmed = line.trim();
      if (trimmed === '') {
        blanks++;
      } else if (this.isComment(trimmed)) {
        comments++;
      } else {
        loc++;
      }
    }
    
    return {
      lines: lines.length,
      loc,
      comments,
      blanks,
      complexity: this.calculateCyclomaticComplexity(content),
    };
  }

  private isComment(line: string): boolean {
    const commentPatterns = [
      /^\s*\/\//, // JS/TS single line
      /^\s*\/\*/, // JS/TS multi line start
      /^\s*\*/, // JS/TS multi line continuation
      /^\s*#/, // Python, Shell
      /^\s*--/, // SQL, Haskell
    ];
    
    return commentPatterns.some(pattern => pattern.test(line));
  }

  private calculateCyclomaticComplexity(content: string): number {
    // Simplified cyclomatic complexity calculation
    const complexityPatterns = [
      /\bif\b/g,
      /\belse\s+if\b/g,
      /\bwhile\b/g,
      /\bfor\b/g,
      /\bcase\b/g,
      /\bcatch\b/g,
      /\?\s*:/g, // Ternary operator
      /&&/g, // Logical AND
      /\|\|/g, // Logical OR
    ];
    
    let complexity = 1; // Base complexity
    
    for (const pattern of complexityPatterns) {
      const matches = content.match(pattern);
      if (matches) {
        complexity += matches.length;
      }
    }
    
    return complexity;
  }

  private extractDependencies(content: string, language: string): string[] {
    const dependencies: string[] = [];
    
    if (language === 'typescript' || language === 'javascript') {
      // Extract import statements
      const importRegex = /import\s+.*\s+from\s+['"]([^'"]+)['"]/g;
      const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
      
      let match;
      while ((match = importRegex.exec(content)) !== null) {
        dependencies.push(match[1]);
      }
      while ((match = requireRegex.exec(content)) !== null) {
        dependencies.push(match[1]);
      }
    }
    
    return [...new Set(dependencies)];
  }

  private extractImports(content: string, language: string): string[] {
    if (language === 'typescript' || language === 'javascript') {
      const imports: string[] = [];
      const regex = /import\s+(?:{([^}]+)}|(\w+)|(\*\s+as\s+\w+))\s+from\s+['"]([^'"]+)['"]/g;
      
      let match;
      while ((match = regex.exec(content)) !== null) {
        if (match[1]) {
          // Named imports
          imports.push(...match[1].split(',').map(s => s.trim()));
        } else if (match[2]) {
          // Default import
          imports.push(match[2]);
        } else if (match[3]) {
          // Namespace import
          imports.push(match[3]);
        }
      }
      
      return imports;
    }
    
    return [];
  }

  private extractExports(content: string, language: string): string[] {
    if (language === 'typescript' || language === 'javascript') {
      const exports: string[] = [];
      
      // Named exports
      const namedExportRegex = /export\s+(?:const|let|var|function|class)\s+(\w+)/g;
      let match;
      while ((match = namedExportRegex.exec(content)) !== null) {
        exports.push(match[1]);
      }
      
      // Export statements
      const exportStmtRegex = /export\s+{([^}]+)}/g;
      while ((match = exportStmtRegex.exec(content)) !== null) {
        exports.push(...match[1].split(',').map(s => s.trim().split(/\s+as\s+/)[0]));
      }
      
      return [...new Set(exports)];
    }
    
    return [];
  }

  private extractFunctions(content: string, language: string): FunctionInfo[] {
    const functions: FunctionInfo[] = [];
    
    if (language === 'typescript' || language === 'javascript') {
      // Function declarations
      const funcRegex = /(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g;
      const arrowRegex = /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s*=>/g;
      
      const lines = content.split('\n');
      
      let match;
      while ((match = funcRegex.exec(content)) !== null) {
        const lineNumber = content.substring(0, match.index).split('\n').length;
        functions.push({
          name: match[1],
          line: lineNumber,
          params: match[2].split(',').map(p => p.trim()).filter(p => p),
          complexity: 1, // Would need proper AST parsing for accurate complexity
          length: this.getFunctionLength(content, match.index),
        });
      }
      
      while ((match = arrowRegex.exec(content)) !== null) {
        const lineNumber = content.substring(0, match.index).split('\n').length;
        functions.push({
          name: match[1],
          line: lineNumber,
          params: match[2].split(',').map(p => p.trim()).filter(p => p),
          complexity: 1,
          length: this.getFunctionLength(content, match.index),
        });
      }
    }
    
    return functions;
  }

  private extractClasses(content: string, language: string): any[] {
    const classes: any[] = [];
    
    if (language === 'typescript' || language === 'javascript') {
      const classRegex = /class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([^{]+))?\s*{/g;
      
      let match;
      while ((match = classRegex.exec(content)) !== null) {
        const lineNumber = content.substring(0, match.index).split('\n').length;
        classes.push({
          name: match[1],
          line: lineNumber,
          extends: match[2],
          implements: match[3]?.split(',').map(i => i.trim()),
          methods: [], // Would need proper AST parsing
          properties: [],
        });
      }
    }
    
    return classes;
  }

  private getFunctionLength(content: string, startIndex: number): number {
    // Simplified function length calculation
    // In reality, would need proper AST parsing
    const afterFunction = content.substring(startIndex);
    const lines = afterFunction.split('\n');
    
    let braceCount = 0;
    let lineCount = 0;
    
    for (const line of lines) {
      lineCount++;
      braceCount += (line.match(/{/g) || []).length;
      braceCount -= (line.match(/}/g) || []).length;
      
      if (braceCount === 0 && lineCount > 1) {
        return lineCount;
      }
    }
    
    return lineCount;
  }

  private analyzeComplexity(content: string, language: string): ComplexityReport {
    const complexity = this.calculateCyclomaticComplexity(content);
    const loc = content.split('\n').filter(line => line.trim() && !this.isComment(line.trim())).length;
    
    // Simplified maintainability index
    const maintainabilityIndex = Math.max(0, Math.min(100, 
      171 - 5.2 * Math.log(complexity) - 0.23 * complexity - 16.2 * Math.log(loc)
    ));
    
    const suggestions = [];
    
    if (complexity > 10) {
      suggestions.push({
        type: 'refactor' as const,
        description: 'Consider breaking this code into smaller functions',
        severity: complexity > 20 ? 'high' as const : 'medium' as const,
      });
    }
    
    if (loc > 200) {
      suggestions.push({
        type: 'split' as const,
        description: 'This file is getting large. Consider splitting it into multiple modules',
        severity: loc > 500 ? 'high' as const : 'medium' as const,
      });
    }
    
    if (maintainabilityIndex < 50) {
      suggestions.push({
        type: 'simplify' as const,
        description: 'Code maintainability is low. Consider refactoring for clarity',
        severity: 'high' as const,
      });
    }
    
    return {
      cyclomatic: complexity,
      cognitive: complexity * 1.2, // Simplified cognitive complexity
      maintainabilityIndex,
      suggestions,
    };
  }
}