"""
Agent d'analyse de code individuel (CAE)
"""

import os
import re
import pathlib
import asyncio
from typing import List, Optional

from src.agents.base_agent import BaseAgent
from src.core.config import AnalysisConfig
from src.models.data_models import FileAnalysis, FileDependency


class CodeAnalysisExpert(BaseAgent):
    """Agent d'analyse de code individuel (CAE)"""
    
    def __init__(self, config: AnalysisConfig, dependency_analyzer=None, doc_searcher=None, code_generator=None):
        super().__init__(config)
        self.dependency_analyzer = dependency_analyzer
        self.doc_searcher = doc_searcher
        self.code_generator = code_generator
    
    def detect_language(self, file_path: str) -> str:
        """Détecte le langage du fichier basé sur l'extension"""
        ext = pathlib.Path(file_path).suffix.lower()
        lang_map = {
            '.dart': 'Dart',
            '.ts': 'TypeScript',
            '.tsx': 'TypeScript (React)',
            '.js': 'JavaScript',
            '.jsx': 'JavaScript (React)',
            '.py': 'Python',
            '.java': 'Java',
            '.kt': 'Kotlin',
            '.swift': 'Swift',
            '.go': 'Go',
            '.rs': 'Rust',
            '.cpp': 'C++',
            '.c': 'C',
            '.h': 'C/C++ Header',
            '.cs': 'C#',
            '.php': 'PHP',
            '.rb': 'Ruby',
            '.sh': 'Shell',
            '.yaml': 'YAML',
            '.yml': 'YAML',
            '.json': 'JSON',
            '.xml': 'XML',
            '.md': 'Markdown',
            '.sql': 'SQL',
            '.html': 'HTML',
            '.css': 'CSS',
            '.scss': 'SCSS',
            '.sass': 'SASS',
        }
        return lang_map.get(ext, 'Unknown')
    
    async def analyze_file(self, file_path: str) -> FileAnalysis:
        """Analyse un fichier individuel avec Gemini"""
        try:
            # Lire le contenu du fichier
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()
            
            if not content.strip():
                language = self.detect_language(file_path)
                relative_path = os.path.relpath(file_path, self.config.root_dir)
                relative_path = relative_path.replace('\\', '/')
                
                # Générer une analyse conforme au template même pour les fichiers vides
                empty_analysis = f"""Voici l'analyse structurée du fichier `{relative_path}`.

# Analyse: {relative_path}

## Langage détecté

{language}

## Objectif / Fonction principale

Fichier vide. Vérifier si ce fichier est nécessaire ou s'il doit être supprimé.

## Points forts / Bonnes pratiques

Aucun point fort identifié pour un fichier vide.

## Risques, dettes techniques ou incohérences

- **Fichier vide :** Ce fichier ne contient aucun code. Il peut s'agir d'un fichier oublié, d'un placeholder non complété, ou d'un fichier à supprimer.

## Suggestions d'amélioration

1.  **Vérifier la nécessité du fichier :**
    Si le fichier n'est pas utilisé, le supprimer pour éviter la confusion.

2.  **Compléter le fichier si nécessaire :**
    Si le fichier doit contenir du code, l'implémenter selon les besoins du projet.
"""
                
                return FileAnalysis(
                    file_path=file_path,
                    language=language,
                    objective="Fichier vide",
                    strengths=[],
                    risks=["Fichier vide - vérifier si nécessaire"],
                    suggestions=["Vérifier la nécessité du fichier", "Compléter le fichier si nécessaire"],
                    analysis_markdown=empty_analysis,
                    success=True,
                    dependencies=[],
                    inconsistencies=[]
                )
            
            language = self.detect_language(file_path)
            relative_path = os.path.relpath(file_path, self.config.root_dir)
            # Normaliser les séparateurs pour utiliser des slashes (comme dans le template)
            relative_path = relative_path.replace('\\', '/')
            
            # Extraire les dépendances si l'analyseur est disponible
            dependencies = []
            dependencies_info = ""
            inconsistencies = []
            
            if self.dependency_analyzer:
                dependencies = self.dependency_analyzer.extract_dependencies(file_path, content, language)
                
                # Préparer les informations sur les dépendances
                if dependencies:
                    deps_list = []
                    missing_deps = []
                    for dep in dependencies:
                        if dep.exists and dep.resolved_path:
                            rel_dep_path = os.path.relpath(dep.resolved_path, self.config.root_dir).replace('\\', '/')
                            deps_list.append(f"  - Ligne {dep.line_number}: `{dep.import_path}` → `{rel_dep_path}` ✅")
                        else:
                            missing_deps.append(f"  - Ligne {dep.line_number}: `{dep.import_path}` ❌ (fichier introuvable)")
                            inconsistencies.append(f"Import introuvable: `{dep.import_path}` à la ligne {dep.line_number}")
                    
                    if deps_list:
                        dependencies_info = "\n\nDépendances détectées:\n" + "\n".join(deps_list)
                    if missing_deps:
                        dependencies_info += "\n\n⚠️ Imports introuvables:\n" + "\n".join(missing_deps)
            
            # Rechercher de la documentation en ligne si activé
            web_docs = ""
            if self.doc_searcher:
                try:
                    web_docs = await self.doc_searcher.search_documentation(language, file_path, content)
                except Exception as e:
                    print(f"⚠️  Erreur lors de la recherche de documentation pour {relative_path}: {e}")
            
            # Générer du code d'analyse approfondie (si activé)
            generated_code_info = ""
            if self.code_generator and self.config.enable_code_generation:
                try:
                    # Générer du code d'analyse pour mieux comprendre le code source
                    analysis_code = self.code_generator.generate_analysis_code(
                        content[:5000], 
                        language, 
                        "Analyse approfondie de la structure, des dépendances et des patterns"
                    )
                    if analysis_code:
                        generated_code_info = f"\n\n## Code d'analyse généré pour compréhension approfondie\n\n```{language.lower()}\n{analysis_code[:2000]}\n```\n"
                except Exception as e:
                    print(f"⚠️  Erreur lors de la génération de code d'analyse pour {relative_path}: {e}")
            
            # Prompt pour l'analyse conforme au template
            prompt = f"""Tu es un expert en analyse de code. Analyse ce fichier et génère une synthèse structurée en Markdown en respectant EXACTEMENT le format suivant.

Fichier: {relative_path}
Langage: {language}
{dependencies_info}

{web_docs}
{generated_code_info}

Contenu du fichier:
```
{content[:50000]}  # Limite à 50k caractères pour éviter les limites de contexte
```

Génère une analyse complète en Markdown avec EXACTEMENT ce format (respecte l'ordre et la structure):

Voici l'analyse structurée du fichier `{relative_path}`.

# Analyse: {relative_path}

## Langage détecté

{language}

## Objectif / Fonction principale

Décris clairement l'objectif et la fonction principale de ce fichier. Peut contenir une liste numérotée des fonctions principales si pertinent.

## Points forts / Bonnes pratiques

- **Titre du point :** Description détaillée
- **Autre point :** Description

Utilise des listes à puces avec des titres en gras suivis de deux-points. Sois spécifique et actionnable.

## Relations et dépendances

Analyse les imports et dépendances de ce fichier. Identifie:
- Les dépendances manquantes ou introuvables
- Les incohérences de types/interfaces entre fichiers
- Les problèmes de couplage ou de dépendances circulaires
- Les exports manquants ou incorrects

Si des dépendances sont listées ci-dessus, analyse chaque relation et détecte les incohérences potentielles (types incompatibles, interfaces manquantes, etc.).

## Risques, dettes techniques ou incohérences

- **Titre du risque :** Description détaillée du problème et de son impact
- **Autre risque :** Description

Utilise des listes à puces avec des titres en gras suivis de deux-points. Sois constructif et précis. Inclus les problèmes détectés dans les relations et dépendances.

## Suggestions d'amélioration

1.  **Titre de l'amélioration :**
    Description détaillée de la suggestion et comment l'implémenter.

2.  **Autre amélioration :**
    Description.

Utilise des listes numérotées avec des titres en gras suivis de deux-points. Fournis des suggestions actionnables et concrètes. Inclus des exemples de code si pertinent.

IMPORTANT:
- Commence toujours par "Voici l'analyse structurée du fichier `{relative_path}`."
- Utilise des slashes (/) pour les chemins, jamais des backslashes
- Respecte exactement l'ordre des sections
- Utilise le format de liste spécifié pour chaque section
- Sois précis, concis et actionnable. Focus sur la qualité du code, la maintenabilité et les bonnes pratiques.
- Si une documentation en ligne est fournie ci-dessus, utilise-la pour enrichir tes suggestions et identifier les meilleures pratiques actuelles."""
            
            # Appel à Gemini avec retry (utilise la méthode de BaseAgent)
            analysis_text = await self._call_gemini_with_retry(prompt)
            
            # Extraire les sections
            objective = self._extract_section(analysis_text, "Objectif", "Points forts")
            strengths = self._extract_list_items(analysis_text, "Points forts", "Relations")
            # Extraire les relations si présentes
            relations_section = self._extract_section(analysis_text, "Relations", "Risques")
            if not relations_section:
                # Essayer sans la section Relations
                strengths = self._extract_list_items(analysis_text, "Points forts", "Risques")
            risks = self._extract_list_items(analysis_text, "Risques", "Suggestions")
            suggestions = self._extract_list_items(analysis_text, "Suggestions", None)
            
            # Extraire les incohérences depuis la section Relations ou Risques
            if relations_section:
                # Chercher des incohérences mentionnées dans la section Relations
                relation_lines = relations_section.split('\n')
                for line in relation_lines:
                    if any(keyword in line.lower() for keyword in ['incohérence', 'manquant', 'introuvable', 'incompatible', 'erreur']):
                        if line.strip() and not line.strip().startswith('#'):
                            inconsistencies.append(line.strip())
            
            return FileAnalysis(
                file_path=file_path,
                language=language,
                objective=objective or "Non spécifié",
                strengths=strengths,
                risks=risks,
                suggestions=suggestions,
                analysis_markdown=analysis_text,
                success=True,
                dependencies=dependencies,
                inconsistencies=inconsistencies
            )
            
        except Exception as e:
            return FileAnalysis(
                file_path=file_path,
                language=self.detect_language(file_path),
                objective="Erreur lors de l'analyse",
                strengths=[],
                risks=[f"Erreur: {str(e)}"],
                suggestions=[],
                analysis_markdown="",
                success=False,
                error=str(e)
            )
    
    def _extract_section(self, text: str, start_marker: str, end_marker: Optional[str]) -> str:
        """Extrait une section du texte entre deux marqueurs"""
        pattern = f"## {start_marker}[^\n]*\n(.*?)(?=## {end_marker}|$)" if end_marker else f"## {start_marker}[^\n]*\n(.*?)$"
        match = re.search(pattern, text, re.DOTALL | re.IGNORECASE)
        if match:
            return match.group(1).strip()
        return ""
    
    def _extract_list_items(self, text: str, start_marker: str, end_marker: Optional[str]) -> List[str]:
        """Extrait les éléments de liste d'une section"""
        section = self._extract_section(text, start_marker, end_marker)
        if not section:
            return []
        
        # Extraire les items de liste (bullet points)
        items = re.findall(r'^[-*+]\s+(.+)$', section, re.MULTILINE)
        if not items:
            # Essayer avec numérotation
            items = re.findall(r'^\d+\.\s+(.+)$', section, re.MULTILINE)
        if not items:
            # Prendre les lignes non vides
            items = [line.strip() for line in section.split('\n') if line.strip() and not line.strip().startswith('#')]
        
        return [item.strip() for item in items if item.strip()]

