import json
from typing import Dict, List, Any, Optional, Union, Tuple
from .llm import LLM

class DeepL(LLM):
    """
    Classe pour l'intégration avec l'API DeepL
    Cette classe hérite de la classe de base LLM et permet de faire des traductions
    """
    
    def __init__(self):
        """
        Initialisation des attributs spécifiques à DeepL
        """
        super().__init__()
        
        # Attributs spécifiques à DeepL
        self.langueSource: str = "FR"
        self.langueDesti: str = "EN"
        self.context: str = ""
        self.split_sentences: str = "0"
        self.preserve_formatting: bool = True
        self.formality: str = "default"  # Options: more, less, prefer_more, prefer_less
        self.show_billed_characters: bool = False
        self.tag_handling: str = ""  # Options: xml, html
        self.outline_detection: bool = True
        self.non_splitting_tags: List[str] = []
        self.splitting_tags: List[str] = []
        self.ignore_tags: List[str] = []
        
        # Constantes publiques (modifiées en attributs en Python)
        self.glossaire_id: Dict[str, str] = {}  # tableau associatif (ccSansCasse) de chaînes
        self._m_tabGlossaireListePaire: List[List[str]] = []  # tableau de 0 par 2 chaînes
        
        # Initialisation par défaut
        self.langueSource = "FR"
        self.langueDesti = "EN"
        self.Modele = "prefer_quality_optimized"
        self.split_sentences = "0"
        self.preserve_formatting = True
        self.formality = "default"
        self.show_billed_characters = False
        self.tag_handling = ""
        self.outline_detection = True
    
    def commandeAutorisation(self) -> str:
        """
        Retourne la commande d'autorisation pour DeepL
        """
        return "DeepL-Auth-Key"
    
    def cleAPI(self) -> str:
        """
        Retourne la clé API DeepL
        """
        return "d42ee2f7-f4e6-d437-3237-fa40b4f45e65"
    
    def urlBase(self) -> str:
        """
        Retourne l'URL de base de l'API DeepL
        """
        return "https://api.deepl.com/v2/"
    
    def urlFonction(self) -> str:
        """
        Retourne l'URL de la fonction par défaut (translate)
        """
        return "translate"
    
    def model_list(self) -> List[str]:
        """
        Retourne la liste des modèles disponibles pour DeepL
        """
        return ["quality_optimized", "latency_optimized", "prefer_quality_optimized"]
    
    def glossaire_liste_paire_possible(self) -> List[List[str]]:
        """
        Récupère la liste des paires de langues possibles pour les glossaires
        """
        import requests
        
        if len(self._m_tabGlossaireListePaire) > 1:
            return self._m_tabGlossaireListePaire
        
        url = self.urlBase() + "glossary-language-pairs"
        headers = {
            "Content-Type": "application/json"
        }
        
        if self.cleAPI() != "":
            headers["Authorization"] = f"{self.commandeAutorisation()} {self.cleAPI()}"
        
        try:
            response = requests.get(url=url, headers=headers)
            
            if response.status_code == 200:
                data = json.loads(response.text)
                self._m_tabGlossaireListePaire = []
                
                for item in data["supported_languages"]:
                    self._m_tabGlossaireListePaire.append([
                        item["source_lang"], 
                        item["target_lang"]
                    ])
            else:
                self._m_tabGlossaireListePaire.append([response.text])
        except Exception as e:
            self._m_tabGlossaireListePaire.append([str(e)])
            
        return self._m_tabGlossaireListePaire
    
    def _even_LLM_POST(self, question: str) -> None:
        """
        Préparation du contenu de la requête pour DeepL
        """
        # Paramètre principal - le texte à traduire
        self._Contenu["text"] = [question]
        self._Contenu["source_lang"] = self.langueSource
        self._Contenu["target_lang"] = self.langueDesti
        
        # Ajout du contexte si défini
        if self.context:
            self._Contenu["context"] = self.context
        
        # Définition du modèle
        self._Contenu["model_type"] = self.Modele
        
        # Options supplémentaires
        self._Contenu["split_sentences"] = self.split_sentences
        self._Contenu["preserve_formatting"] = self.preserve_formatting
        self._Contenu["formality"] = self.formality
        
        # Ajout du glossaire si disponible
        glossaire_id = self._glossaireRetrouveID(self.langueSource, self.langueDesti)
        if glossaire_id:
            self._Contenu["glossary_id"] = glossaire_id
        
        # Options avancées
        self._Contenu["show_billed_characters"] = self.show_billed_characters
        self._Contenu["tag_handling"] = self.tag_handling
        self._Contenu["outline_detection"] = self.outline_detection
        
        # Ajout des tags non-splittants si définis
        if self.non_splitting_tags:
            self._Contenu["non_splitting_tags"] = self.non_splitting_tags
        
        # Ajout des tags splittants si définis
        if self.splitting_tags:
            self._Contenu["splitting_tags"] = self.splitting_tags
        
        # Ajout des tags à ignorer si définis
        if self.ignore_tags:
            self._Contenu["ignore_tags"] = self.ignore_tags
    
    def _interrogerRetourneReponse(self, reponse: str) -> str:
        """
        Extraction de la réponse à partir du JSON retourné par DeepL
        """
        data = json.loads(reponse)
        return data["translations"][0]["text"]
    
    def glossaire_cree(self, sLanguageSource: str, sLangageDesti: str, sEntrees: str, sFormat: str = "tsv") -> str:
        """
        Crée un glossaire avec les entrées fournies
        Format des entrées:
            - tsv : source<tab>cible<RC>
            - csv : source,cible<RC>
        """
        import requests
        
        # Supprime le glossaire existant si présent
        sID = self._glossaireRetrouveID(sLanguageSource, sLangageDesti)
        if sID:
            self._glossaireSupprime(sID)
        
        url = self.urlBase() + "glossaries"
        headers = {
            "Content-Type": "application/json"
        }
        
        if self.cleAPI():
            headers["Authorization"] = f"{self.commandeAutorisation()} {self.cleAPI()}"
        
        # Préparation des paramètres
        params = {
            "name": f"{sLanguageSource.upper()}_{sLangageDesti.upper()}",
            "entries": sEntrees,
            "source_lang": sLanguageSource,
            "target_lang": sLangageDesti,
            "entries_format": sFormat
        }
        
        try:
            response = requests.post(url=url, headers=headers, json=params)
            
            if response.status_code == 201:
                data = json.loads(response.text)
                return data["glossary_id"]
            else:
                return response.text
        except Exception as e:
            return str(e)
    
    def _glossaireRetrouveID(self, sLanguageSource: str, sLangageDesti: str) -> str:
        """
        Récupère l'ID d'un glossaire existant pour une paire de langues
        """
        import requests
        
        # Création de la désignation pour la paire de langues
        designation = f"{sLanguageSource.upper()}_{sLangageDesti.upper()}"
        
        # Retourne l'ID du glossaire si déjà en cache
        if designation in self.glossaire_id:
            return self.glossaire_id[designation]
        
        url = self.urlBase() + "glossaries"
        headers = {
            "Content-Type": "application/json"
        }
        
        if self.cleAPI():
            headers["Authorization"] = f"{self.commandeAutorisation()} {self.cleAPI()}"
        
        try:
            response = requests.get(url=url, headers=headers)
            
            if response.status_code == 200:
                data = json.loads(response.text)
                
                # Mise à jour du cache des glossaires
                self.glossaire_id.clear()
                for glossaire in data["glossaries"]:
                    glossaire_designation = f"{glossaire['source_lang'].upper()}_{glossaire['target_lang'].upper()}"
                    self.glossaire_id[glossaire_designation] = glossaire["glossary_id"]
                
                # Retourne l'ID du glossaire demandé
                designation = f"{sLanguageSource.upper()}_{sLangageDesti.upper()}"
                return self.glossaire_id.get(designation, "")
            else:
                return response.text
        except Exception as e:
            return str(e)
    
    def _glossaireSupprime(self, sID: str) -> str:
        """
        Supprime un glossaire existant
        """
        import requests
        
        url = self.urlBase() + f"glossaries/{sID}"
        headers = {
            "Content-Type": "application/json"
        }
        
        if self.cleAPI():
            headers["Authorization"] = f"{self.commandeAutorisation()} {self.cleAPI()}"
        
        try:
            response = requests.delete(url=url, headers=headers)
            
            # Suppression de l'entrée dans le cache
            for designation, id_en_cours in list(self.glossaire_id.items()):
                if id_en_cours == sID:
                    del self.glossaire_id[designation]
            
            if response.status_code == 204:
                return ""
            else:
                return response.text
        except Exception as e:
            return str(e) 