#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Agent de questions-réponses utilisant MistralAPI
"""

import os
import sys
import json
import argparse
from pathlib import Path
from typing import Dict, List, Any, Optional
from datetime import datetime

# Ajouter le répertoire parent au sys.path pour importer les modules
sys.path.append(str(Path(__file__).parent.parent))

from agents.base_agent import Agent
from core.factory import LLMFactory

class AgentQuestionReponse(Agent):
    """
    Agent spécialisé dans les questions-réponses utilisant Mistral API
    """
    
    def __init__(self, nom: str, modele: str = "mistral-large-latest"):
        """
        Initialise l'agent avec un nom et un modèle Mistral
        
        Args:
            nom: Nom de l'agent
            modele: Modèle Mistral à utiliser
        """
        super().__init__(nom)
        self.llm = LLMFactory().create("mistralapi")
        self.llm.modele = modele
    
    def executer(self, question: str, contexte: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        Exécute une requête de question-réponse
        
        Args:
            question: La question à poser
            contexte: Contexte supplémentaire pour la question (optionnel)
            
        Returns:
            Dictionnaire contenant la réponse et les métadonnées
        """
        # Formater le prompt avec le contexte si disponible
        prompt = self._construire_prompt(question, contexte)
        
        try:
            # Générer la réponse
            reponse = self.llm.generate(prompt)
            
            # Enregistrer dans l'historique
            input_data = {
                "type": "question",
                "contenu": question,
                "contexte": contexte
            }
            output_data = {
                "type": "reponse",
                "contenu": reponse
            }
            self.ajouter_historique("generation_reponse", input_data, output_data)
            
            # Préparer le résultat
            resultat = {
                "question": question,
                "reponse": reponse,
                "timestamp": datetime.now().isoformat(),
                "modele": self.llm.modele
            }
            
            if contexte:
                resultat["contexte_utilise"] = True
                
            return resultat
            
        except Exception as e:
            return {
                "erreur": str(e),
                "question": question,
                "timestamp": datetime.now().isoformat()
            }
    
    def _construire_prompt(self, question: str, contexte: Optional[Dict[str, Any]] = None) -> str:
        """
        Construit le prompt en fonction de la question et du contexte
        """
        if not contexte:
            return question
        
        # Formater le contexte en texte
        contexte_texte = self._formater_contexte(contexte)
        
        # Construire le prompt avec le contexte
        prompt = f"""Contexte :
{contexte_texte}

Question : {question}

Réponds à la question ci-dessus en utilisant le contexte fourni. 
Si le contexte ne suffit pas pour répondre complètement, indique-le clairement.
"""
        return prompt
    
    def _formater_contexte(self, contexte: Dict[str, Any]) -> str:
        """
        Formate le contexte en texte lisible
        """
        if isinstance(contexte, str):
            return contexte
            
        if isinstance(contexte, dict):
            # Si le contexte est un dictionnaire JSON
            try:
                return json.dumps(contexte, ensure_ascii=False, indent=2)
            except:
                parts = []
                for key, value in contexte.items():
                    parts.append(f"{key}: {value}")
                return "\n".join(parts)
        
        # Fallback pour d'autres types
        return str(contexte)
    
    def generer_questions(self, contexte: Dict[str, Any], nombre: int = 3) -> List[str]:
        """
        Génère des questions pertinentes basées sur un contexte
        
        Args:
            contexte: Le contexte à partir duquel générer des questions
            nombre: Nombre de questions à générer
            
        Returns:
            Liste des questions générées
        """
        contexte_texte = self._formater_contexte(contexte)
        
        prompt = f"""À partir du contexte suivant :
{contexte_texte}

Génère {nombre} questions pertinentes et intéressantes qui pourraient être posées sur ce contenu.
Format attendu : une question par ligne, numérotée (1., 2., etc.)
"""
        
        try:
            reponse = self.llm.generate(prompt)
            
            # Extraire les questions de la réponse
            questions = []
            for ligne in reponse.split('\n'):
                ligne = ligne.strip()
                if ligne and (ligne[0].isdigit() and ligne[1:3] in ['. ', '- ', ') ']):
                    # Extraire la question après le numéro
                    question = ligne[ligne.find(' ')+1:].strip()
                    questions.append(question)
            
            # Si l'extraction a échoué, retourner la réponse brute divisée
            if not questions and reponse:
                questions = [q.strip() for q in reponse.split('\n') if q.strip()]
                
            return questions[:nombre]  # Limiter au nombre demandé
            
        except Exception as e:
            print(f"Erreur lors de la génération de questions: {e}")
            return []
    
    def evaluer_reponse(self, question: str, reponse: str, reference: Optional[str] = None) -> Dict[str, Any]:
        """
        Évalue la qualité d'une réponse à une question
        
        Args:
            question: La question posée
            reponse: La réponse à évaluer
            reference: Réponse de référence (optionnelle)
            
        Returns:
            Dictionnaire contenant l'évaluation et les scores
        """
        if reference:
            prompt = f"""Question : {question}

Réponse à évaluer : 
{reponse}

Réponse de référence : 
{reference}

Évalue la réponse fournie par rapport à la réponse de référence. Attribue un score pour chaque critère :
1. Précision (1-10) : La réponse est-elle factuelle et correcte ?
2. Complétude (1-10) : La réponse couvre-t-elle tous les aspects importants ?
3. Clarté (1-10) : La réponse est-elle claire et facile à comprendre ?

Pour chaque critère, justifie brièvement ton score. Termine par une note globale sur 10.
"""
        else:
            prompt = f"""Question : {question}

Réponse à évaluer : 
{reponse}

Évalue la qualité de cette réponse. Attribue un score pour chaque critère :
1. Précision (1-10) : La réponse semble-t-elle factuelle et correcte ?
2. Complétude (1-10) : La réponse semble-t-elle couvrir tous les aspects importants ?
3. Clarté (1-10) : La réponse est-elle claire et facile à comprendre ?

Pour chaque critère, justifie brièvement ton score. Termine par une note globale sur 10.
"""
        
        try:
            evaluation = self.llm.generate(prompt)
            
            # Tenter d'extraire les scores numériques
            scores = {}
            
            for ligne in evaluation.split('\n'):
                if "précision" in ligne.lower() and ":" in ligne:
                    try:
                        score = int([s for s in ligne.split() if s.isdigit()][0])
                        scores["precision"] = score
                    except:
                        pass
                
                elif "complétude" in ligne.lower() and ":" in ligne:
                    try:
                        score = int([s for s in ligne.split() if s.isdigit()][0])
                        scores["completude"] = score
                    except:
                        pass
                
                elif "clarté" in ligne.lower() and ":" in ligne:
                    try:
                        score = int([s for s in ligne.split() if s.isdigit()][0])
                        scores["clarte"] = score
                    except:
                        pass
                
                elif "globale" in ligne.lower() and ":" in ligne:
                    try:
                        score = int([s for s in ligne.split() if s.isdigit()][0])
                        scores["globale"] = score
                    except:
                        pass
            
            return {
                "evaluation_detaillee": evaluation,
                "scores": scores
            }
            
        except Exception as e:
            return {
                "erreur": str(e),
                "evaluation_detaillee": "Échec de l'évaluation"
            }

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Agent de Questions-Réponses avec Mistral API")
    parser.add_argument("--question", help="Question à poser")
    parser.add_argument("--contexte", help="Chemin vers un fichier JSON de contexte")
    parser.add_argument("--model", default="mistral-large-latest", help="Modèle Mistral à utiliser")
    parser.add_argument("--generer-questions", action="store_true", help="Générer des questions à partir du contexte")
    parser.add_argument("--nombre", type=int, default=3, help="Nombre de questions à générer")
    parser.add_argument("--evaluer", help="Réponse à évaluer (nécessite --question)")
    parser.add_argument("--reference", help="Réponse de référence pour l'évaluation")
    
    args = parser.parse_args()
    
    # Vérification de la clé API
    if not os.environ.get("MISTRAL_API_KEY"):
        print("Erreur: Variable d'environnement MISTRAL_API_KEY non définie.")
        print("Veuillez définir cette variable avec votre clé API Mistral.")
        print("Exemple: export MISTRAL_API_KEY=votre_clé_api")
        sys.exit(1)
    
    # Initialisation de l'agent
    agent = AgentQuestionReponse("AgentQR", modele=args.model)
    
    # Chargement du contexte si spécifié
    contexte = None
    if args.contexte:
        try:
            with open(args.contexte, 'r', encoding='utf-8') as f:
                contexte = json.load(f)
            print(f"Contexte chargé depuis {args.contexte}")
        except Exception as e:
            print(f"Erreur lors du chargement du contexte: {e}")
            sys.exit(1)
    
    # Génération de questions à partir du contexte
    if args.generer_questions and contexte:
        print(f"\n=== Génération de {args.nombre} questions à partir du contexte ===")
        questions = agent.generer_questions(contexte, nombre=args.nombre)
        
        print("\nQuestions générées:")
        for i, question in enumerate(questions, 1):
            print(f"{i}. {question}")
        sys.exit(0)
    
    # Évaluation d'une réponse
    if args.evaluer and args.question:
        print("\n=== Évaluation de la réponse ===")
        evaluation = agent.evaluer_reponse(args.question, args.evaluer, args.reference)
        
        if "erreur" in evaluation:
            print(f"Erreur: {evaluation['erreur']}")
        else:
            print("\nÉvaluation détaillée:")
            print(evaluation["evaluation_detaillee"])
            
            if evaluation.get("scores"):
                print("\nScores:")
                for critere, score in evaluation["scores"].items():
                    print(f"- {critere.capitalize()}: {score}/10")
        
        sys.exit(0)
    
    # Traitement d'une question simple
    if args.question:
        print(f"\n=== Traitement de la question avec le modèle {args.model} ===")
        print(f"Question: {args.question}")
        
        resultat = agent.executer(args.question, contexte)
        
        if "erreur" in resultat:
            print(f"Erreur: {resultat['erreur']}")
        else:
            print("\nRéponse:")
            print(resultat["reponse"])
        
        sys.exit(0)
    
    # Si aucune action spécifiée
    parser.print_help() 