from .base_agent import BaseAgent
from typing import Any, Dict
import logging
import os
from PIL import Image
import base64
import io

logger = logging.getLogger("AgentImageAnalyser")

class AgentImageAnalyser(BaseAgent):
    """
    Agent pour analyser les images et extraire les informations pertinentes.
    """
    def __init__(self, llm):
        super().__init__("AgentImageAnalyser", llm)
        
        # Configuration locale de l'agent (remplace AgentConfig)
        self.temperature = 0.3
        self.top_p = 0.9
        self.max_tokens = 1200
        self.system_prompt = """Tu es un expert en analyse d'images pour le support technique de BRG-Lab.
Ta mission est d'analyser des captures d'écran en lien avec le contexte du ticket de support.

Structure ton analyse d'image de façon factuelle:
1. Description objective: Ce que montre l'image (interface, message d'erreur, code, etc.)
2. Éléments techniques clés: Versions, codes d'erreur, paramètres visibles, messages du système
3. Relation avec le problème: Comment cette image se rapporte au problème décrit dans le ticket

IMPORTANT:
- Ne fais PAS d'interprétation complexe ou de diagnostic
- Ne propose PAS de solutions ou recommandations
- Reste strictement factuel et objectif dans ta description
- Concentre-toi uniquement sur ce qui est visible dans l'image
- Ne répète pas les informations du ticket sauf si elles sont visibles dans l'image

Ton analyse sera utilisée comme élément factuel pour un rapport technique plus complet."""
        
        # Appliquer la configuration au LLM
        self._appliquer_config_locale()
        
        logger.info("AgentImageAnalyser initialisé")
    
    def _appliquer_config_locale(self) -> None:
        """
        Applique la configuration locale au modèle LLM.
        """
        # Appliquer le prompt système
        if hasattr(self.llm, "prompt_system"):
            self.llm.prompt_system = self.system_prompt
        
        # Appliquer les paramètres
        if hasattr(self.llm, "configurer"):
            params = {
                "temperature": self.temperature,
                "top_p": self.top_p,
                "max_tokens": self.max_tokens
            }
            
            # Ajustements selon le type de modèle
            if "mistral_medium" in self.llm.__class__.__name__.lower():
                params["temperature"] += 0.05
                params["max_tokens"] = 1000
            elif "pixtral" in self.llm.__class__.__name__.lower():
                params["temperature"] -= 0.05
            elif "ollama" in self.llm.__class__.__name__.lower():
                params["temperature"] += 0.1
                params.update({
                    "num_ctx": 2048,
                    "repeat_penalty": 1.1,
                })
            
            self.llm.configurer(**params)
            
    def _verifier_image(self, image_path: str) -> bool:
        """
        Vérifie si l'image existe et est accessible
        
        Args:
            image_path: Chemin vers l'image
            
        Returns:
            True si l'image existe et est accessible, False sinon
        """
        try:
            # Vérifier que le fichier existe
            if not os.path.exists(image_path):
                logger.error(f"L'image n'existe pas: {image_path}")
                return False
            
            # Vérifier que le fichier est accessible en lecture
            if not os.access(image_path, os.R_OK):
                logger.error(f"L'image n'est pas accessible en lecture: {image_path}")
                return False
            
            # Vérifier que le fichier peut être ouvert comme une image
            with Image.open(image_path) as img:
                # Vérifier les dimensions de l'image
                width, height = img.size
                if width <= 0 or height <= 0:
                    logger.error(f"Dimensions d'image invalides: {width}x{height}")
                    return False
                
                logger.info(f"Image vérifiée avec succès: {image_path} ({width}x{height})")
                return True
        except Exception as e:
            logger.error(f"Erreur lors de la vérification de l'image {image_path}: {str(e)}")
            return False
    
    def _encoder_image_base64(self, image_path: str) -> str:
        """
        Encode l'image en base64 pour l'inclure directement dans le prompt
        
        Args:
            image_path: Chemin vers l'image
            
        Returns:
            Chaîne de caractères au format data URI avec l'image encodée en base64
        """
        try:
            # Ouvrir l'image et la redimensionner si trop grande
            with Image.open(image_path) as img:
                # Redimensionner l'image si elle est trop grande (max 800x800)
                max_size = 800
                if img.width > max_size or img.height > max_size:
                    img.thumbnail((max_size, max_size), Image.Resampling.LANCZOS)
                
                # Convertir en RGB si nécessaire (pour les formats comme PNG)
                if img.mode != "RGB":
                    img = img.convert("RGB")
                
                # Sauvegarder l'image en JPEG dans un buffer mémoire
                buffer = io.BytesIO()
                img.save(buffer, format="JPEG", quality=85)
                buffer.seek(0)
                
                # Encoder en base64
                img_base64 = base64.b64encode(buffer.read()).decode("utf-8")
                
                # Construire le data URI
                data_uri = f"data:image/jpeg;base64,{img_base64}"
                
                return data_uri
        except Exception as e:
            logger.error(f"Erreur lors de l'encodage de l'image {image_path}: {str(e)}")
            return ""
        
    def executer(self, image_path: str, contexte: str) -> Dict[str, Any]:
        """
        Analyse une image en tenant compte du contexte du ticket
        
        Args:
            image_path: Chemin vers l'image à analyser
            contexte: Contexte du ticket (résultat de l'analyse JSON)
            
        Returns:
            Dictionnaire contenant l'analyse détaillée de l'image et les métadonnées d'exécution
        """
        image_name = os.path.basename(image_path)
        logger.info(f"Analyse de l'image: {image_name} avec contexte")
        print(f"  AgentImageAnalyser: Analyse de {image_name}")
        
        # Vérifier que l'image existe et est accessible
        if not self._verifier_image(image_path):
            error_message = f"L'image n'est pas accessible ou n'est pas valide: {image_name}"
            logger.error(error_message)
            print(f"  ERREUR: {error_message}")
            
            return {
                "analyse": f"ERREUR: {error_message}. Veuillez vérifier que l'image existe et est valide.",
                "error": True,
                "metadata": {
                    "image_path": image_path,
                    "image_name": image_name,
                    "timestamp": self._get_timestamp(),
                    "error": True
                }
            }
            
        # Créer un prompt détaillé pour l'analyse d'image avec le contexte du ticket
        prompt = f"""Analyse cette image en tenant compte du contexte suivant du ticket de support technique:

CONTEXTE DU TICKET:
{contexte}

Fournis une analyse STRICTEMENT FACTUELLE de l'image avec les sections suivantes:
1. Description objective: Ce que montre concrètement l'image
2. Éléments techniques visibles: Messages d'erreur exacts, versions, configurations, paramètres
3. Relation avec le problème: Comment cette image se rapporte au problème décrit

IMPORTANT:
- NE fais PAS d'interprétation ou de diagnostic
- NE propose PAS de solutions
- Reste strictement factuel dans ta description
- Décris UNIQUEMENT ce qui est visible dans l'image
- Cite les textes exacts visibles dans l'image (messages d'erreur, etc.)
"""
        
        try:
            logger.info("Envoi de la requête au LLM")
            
            # Utiliser la méthode interroger_avec_image au lieu de interroger
            if hasattr(self.llm, "interroger_avec_image"):
                logger.info(f"Utilisation de la méthode interroger_avec_image pour {image_name}")
                response = self.llm.interroger_avec_image(image_path, prompt)
            else:
                # Fallback vers la méthode standard avec base64 si interroger_avec_image n'existe pas
                logger.warning(f"La méthode interroger_avec_image n'existe pas, utilisation du fallback pour {image_name}")
                img_base64 = self._encoder_image_base64(image_path)
                if img_base64:
                    prompt_base64 = f"""Analyse cette image:
{img_base64}

En tenant compte du contexte suivant du ticket de support technique:

CONTEXTE DU TICKET:
{contexte}

Fournis une analyse STRICTEMENT FACTUELLE de l'image avec les sections suivantes:
1. Description objective: Ce que montre concrètement l'image
2. Éléments techniques visibles: Messages d'erreur exacts, versions, configurations, paramètres
3. Relation avec le problème: Comment cette image se rapporte au problème décrit

IMPORTANT:
- NE fais PAS d'interprétation ou de diagnostic
- NE propose PAS de solutions
- Reste strictement factuel dans ta description
- Décris UNIQUEMENT ce qui est visible dans l'image
- Cite les textes exacts visibles dans l'image (messages d'erreur, etc.)
"""
                    
                    response = self.llm.interroger(prompt_base64)
                else:
                    error_message = "Impossible d'encoder l'image en base64"
                    logger.error(f"Erreur d'analyse pour {image_name}: {error_message}")
                    print(f"  ERREUR: {error_message}")
                    
                    # Retourner un résultat d'erreur explicite
                    return {
                        "analyse": f"ERREUR: {error_message}. Veuillez vérifier que l'image est dans un format standard.",
                        "error": True,
                        "raw_response": "",
                        "metadata": {
                            "image_path": image_path,
                            "image_name": image_name,
                            "timestamp": self._get_timestamp(),
                            "error": True
                        }
                    }
            
            # Vérifier si la réponse contient des indications que le modèle ne peut pas analyser l'image
            error_phrases = [
                "je ne peux pas directement visualiser",
                "je n'ai pas accès à l'image",
                "je ne peux pas voir l'image",
                "sans accès direct à l'image",
                "je n'ai pas la possibilité de voir",
                "je ne peux pas accéder directement",
                "erreur: impossible d'analyser l'image"
            ]
            
            # Vérifier si une des phrases d'erreur est présente dans la réponse
            if any(phrase in response.lower() for phrase in error_phrases):
                logger.warning(f"Le modèle indique qu'il ne peut pas analyser l'image: {image_name}")
                error_message = "Le modèle n'a pas pu analyser l'image correctement"
                logger.error(f"Erreur d'analyse pour {image_name}: {error_message}")
                print(f"  ERREUR: {error_message}")
                
                # Retourner un résultat d'erreur explicite
                return {
                    "analyse": f"ERREUR: {error_message}. Veuillez vérifier que le modèle a accès à l'image ou utiliser un modèle différent.",
                    "error": True,
                    "raw_response": response,
                    "metadata": {
                        "image_path": image_path,
                        "image_name": image_name,
                        "timestamp": self._get_timestamp(),
                        "error": True
                    }
                }
            
            logger.info(f"Réponse reçue pour l'image {image_name}: {response[:100]}...")
            
            # Créer un dictionnaire de résultat avec l'analyse et les métadonnées
            result = {
                "analyse": response,
                "metadata": {
                    "image_path": image_path,
                    "image_name": image_name,
                    "timestamp": self._get_timestamp(),
                    "model_info": {
                        "model": getattr(self.llm, "modele", str(type(self.llm))),
                        "temperature": self.temperature,
                        "top_p": self.top_p,
                        "max_tokens": self.max_tokens
                    }
                }
            }
            
            # Enregistrer l'analyse dans l'historique avec contexte et prompt
            self.ajouter_historique("analyse_image", 
                                {
                                    "image_path": image_path,
                                    "contexte": contexte,
                                    "prompt": prompt
                                }, 
                                response)
            
            return result
            
        except Exception as e:
            error_message = f"Erreur lors de l'analyse de l'image: {str(e)}"
            logger.error(error_message)
            print(f"  ERREUR: {error_message}")
            
            # Retourner un résultat par défaut en cas d'erreur
            return {
                "analyse": f"ERREUR: {error_message}",
                "error": True,
                "metadata": {
                    "image_path": image_path,
                    "image_name": image_name,
                    "timestamp": self._get_timestamp(),
                    "error": True
                }
            }
    
    def _get_timestamp(self) -> str:
        """Retourne un timestamp au format YYYYMMDD_HHMMSS"""
        from datetime import datetime
        return datetime.now().strftime("%Y%m%d_%H%M%S")