import { GraphQLQuery, GraphQLField } from "@graphql-lint/core";
import fs from "fs";
import path from "path";
import { glob } from "glob";

interface ClintAction {
  name: string;
  pattern: string; // clint.entity.method
  file: string;
  line: number;
}

interface ClintUsageResult {
  name: string;
  pattern: string;
  file: string;
  line: number;
  used: boolean;
  usageLocations?: Array<{
    file: string;
    line: number;
    code: string;
  }>;
}

export class ClintUsageAnalyzer {
  
  async analyzeUsageInPath(
    targetPath: string, 
    actions: ClintAction[], 
    results: ClintUsageResult[], 
    includePatterns: string[], 
    excludePatterns: string[]
  ): Promise<void> {
    // Encontrar arquivos para analisar
    const files = await this.findFilesToAnalyze(targetPath, includePatterns, excludePatterns);
    
    // Para cada action, verificar se está sendo usada
    for (const action of actions) {
      const usageResult: ClintUsageResult = {
        ...action,
        used: false,
        usageLocations: []
      };
      
      // Procurar uso da action nos arquivos
      for (const file of files) {
        const usages = await this.findUsageInFile(file, action.pattern);
        if (usages.length > 0) {
          usageResult.used = true;
          usageResult.usageLocations!.push(...usages);
        }
      }
      
      results.push(usageResult);
    }
  }

  private async findFilesToAnalyze(targetPath: string, includePatterns: string[], excludePatterns: string[]): Promise<string[]> {
    const stats = fs.statSync(targetPath);
    
    if (stats.isFile()) {
      return [targetPath];
    }
    
    // Buscar arquivos TypeScript/JavaScript 
    const tsFiles = await glob("**/*.{ts,tsx,js,jsx}", {
      cwd: targetPath,
      ignore: excludePatterns,
      absolute: true
    });
    
    return tsFiles;
  }

  private async findUsageInFile(filePath: string, pattern: string): Promise<Array<{file: string, line: number, code: string}>> {
    try {
      const content = fs.readFileSync(filePath, 'utf-8');
      const lines = content.split('\n');
      const usages: Array<{file: string, line: number, code: string}> = [];
      
      for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        const lineNumber = i + 1;
        
        // Procurar pelo padrão clint.entity.method
        if (line.includes(pattern)) {
          usages.push({
            file: filePath,
            line: lineNumber,
            code: line.trim()
          });
        }
      }
      
      return usages;
    } catch (error) {
      console.warn(`⚠️  Erro ao analisar arquivo ${filePath}:`, error);
      return [];
    }
  }

  /**
   * Analisa uso de actions customizadas da Clint no código
   * Detecta padrões como: clint.owner.getName, clint.user.createAccount
   */
  analyzeClintUsage(sourceCode: string, filePath: string): Array<{pattern: string, line: number, column: number}> {
    const usages: Array<{pattern: string, line: number, column: number}> = [];
    const lines = sourceCode.split('\n');
    
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i];
      const lineNumber = i + 1;
      
      // Detectar padrões clint.*.* 
      const clintMatches = line.matchAll(/clint\.([a-zA-Z_]+)\.([a-zA-Z_]+)/g);
      
      for (const match of clintMatches) {
        const fullPattern = match[0]; // clint.owner.getName
        const column = match.index || 0;
        
        usages.push({
          pattern: fullPattern,
          line: lineNumber,
          column: column
        });
      }
    }
    
    return usages;
  }

  /**
   * Mapeia uso de padrões Clint para actions do Hasura
   */
  mapClintUsageToActions(clintUsages: Array<{pattern: string, line: number, column: number}>): Array<{actionName: string, line: number, column: number}> {
    return clintUsages.map(usage => ({
      actionName: this.clintPatternToAction(usage.pattern),
      line: usage.line,
      column: usage.column
    }));
  }

  /**
   * Converte padrão Clint para nome de action do Hasura
   * Exemplo: clint.owner.getName -> owner_get_name
   */
  private clintPatternToAction(pattern: string): string {
    const match = pattern.match(/^clint\.([^.]+)\.([^.]+)$/);
    if (!match) {
      return pattern.replace('clint.', '');
    }
    
    const [, entity, method] = match;
    
    // Converter camelCase para snake_case
    const actionPart = method.replace(/([A-Z])/g, '_$1').toLowerCase();
    
    return `${entity}_${actionPart}`;
  }
}

export { ClintAction, ClintUsageResult };
