"""
Module pour la gestion des tables de correspondance CIM-10 / CIM-11.

Ce module permet de maintenir les mappings bidirectionnels entre les codes
CIM-10 et CIM-11 pour faciliter la transition future vers la CIM-11.

Exigences: 24.6, 28.1, 28.2
"""

import logging
from pathlib import Path
from typing import Dict, List, Optional
from dataclasses import dataclass
import yaml
import json

logger = logging.getLogger(__name__)


@dataclass
class CIM11Mapping:
    """
    Représente un mapping entre un code CIM-10 et un ou plusieurs codes CIM-11.
    """
    cim10_code: str
    cim10_label: str
    cim11_codes: List[str]
    cim11_labels: List[str]
    mapping_type: str  # "exact" | "approximate" | "multiple" | "no_match"
    notes: Optional[str] = None


class CIM11Mapper:
    """
    Gestionnaire des tables de correspondance CIM-10 / CIM-11.
    
    Cette classe permet de :
    - Importer les tables de correspondance ATIH
    - Maintenir les mappings bidirectionnels CIM-10 ↔ CIM-11
    - Rechercher les équivalences entre les deux classifications
    
    Exigences: 24.6, 28.1, 28.2
    """
    
    def __init__(self, mappings_dir: str = "data/mappings"):
        """
        Initialise le mapper CIM-11.
        
        Args:
            mappings_dir: Répertoire contenant les fichiers de mapping
        """
        self.mappings_dir = Path(mappings_dir)
        self.cim10_to_cim11: Dict[str, CIM11Mapping] = {}
        self.cim11_to_cim10: Dict[str, List[str]] = {}
        
        logger.info(f"CIM11Mapper initialisé avec mappings_dir={mappings_dir}")
    
    def import_atih_mappings(self, mapping_file: str) -> int:
        """
        Importe les tables de correspondance ATIH depuis un fichier.
        
        Le fichier peut être au format YAML ou JSON et doit contenir
        les mappings CIM-10 → CIM-11 avec les métadonnées.
        
        Format attendu:
        ```yaml
        mappings:
          - cim10_code: "A00.0"
            cim10_label: "Choléra à Vibrio cholerae 01, biovar cholerae"
            cim11_codes: ["1A00.0"]
            cim11_labels: ["Cholera due to Vibrio cholerae O1, biovar cholerae"]
            mapping_type: "exact"
            notes: null
        ```
        
        Args:
            mapping_file: Chemin vers le fichier de mapping
            
        Returns:
            Nombre de mappings importés
            
        Exigences: 28.1, 28.2
        """
        mapping_path = self.mappings_dir / mapping_file
        
        if not mapping_path.exists():
            raise FileNotFoundError(f"Fichier de mapping non trouvé: {mapping_path}")
        
        logger.info(f"Import des mappings CIM-10/CIM-11 depuis {mapping_path}")
        
        # Charger le fichier
        with open(mapping_path, "r", encoding="utf-8") as f:
            if mapping_path.suffix == ".yaml" or mapping_path.suffix == ".yml":
                data = yaml.safe_load(f)
            elif mapping_path.suffix == ".json":
                data = json.load(f)
            else:
                raise ValueError(f"Format de fichier non supporté: {mapping_path.suffix}")
        
        # Extraire les mappings
        mappings_data = data.get("mappings", [])
        
        count = 0
        for mapping_dict in mappings_data:
            mapping = CIM11Mapping(
                cim10_code=mapping_dict["cim10_code"],
                cim10_label=mapping_dict["cim10_label"],
                cim11_codes=mapping_dict["cim11_codes"],
                cim11_labels=mapping_dict["cim11_labels"],
                mapping_type=mapping_dict["mapping_type"],
                notes=mapping_dict.get("notes")
            )
            
            # Ajouter au mapping CIM-10 → CIM-11
            self.cim10_to_cim11[mapping.cim10_code] = mapping
            
            # Ajouter au mapping inverse CIM-11 → CIM-10
            for cim11_code in mapping.cim11_codes:
                if cim11_code not in self.cim11_to_cim10:
                    self.cim11_to_cim10[cim11_code] = []
                self.cim11_to_cim10[cim11_code].append(mapping.cim10_code)
            
            count += 1
        
        logger.info(f"Importé {count} mappings CIM-10/CIM-11")
        return count
    
    def get_cim11_equivalent(self, cim10_code: str) -> Optional[CIM11Mapping]:
        """
        Récupère l'équivalent CIM-11 d'un code CIM-10.
        
        Args:
            cim10_code: Code CIM-10 (ex: "A00.0")
            
        Returns:
            Mapping CIM-11 ou None si aucun mapping n'existe
            
        Exigences: 28.1
        """
        return self.cim10_to_cim11.get(cim10_code)
    
    def get_cim10_equivalents(self, cim11_code: str) -> List[str]:
        """
        Récupère les équivalents CIM-10 d'un code CIM-11.
        
        Args:
            cim11_code: Code CIM-11 (ex: "1A00.0")
            
        Returns:
            Liste de codes CIM-10 équivalents
            
        Exigences: 28.2
        """
        return self.cim11_to_cim10.get(cim11_code, [])
    
    def search_cim11_by_label(self, label: str, max_results: int = 10) -> List[CIM11Mapping]:
        """
        Recherche des codes CIM-11 par libellé.
        
        Args:
            label: Libellé à rechercher
            max_results: Nombre maximum de résultats
            
        Returns:
            Liste de mappings correspondants
        """
        results = []
        label_lower = label.lower()
        
        for mapping in self.cim10_to_cim11.values():
            # Rechercher dans les libellés CIM-10 et CIM-11
            if (label_lower in mapping.cim10_label.lower() or
                any(label_lower in cim11_label.lower() for cim11_label in mapping.cim11_labels)):
                results.append(mapping)
                
                if len(results) >= max_results:
                    break
        
        return results
    
    def get_mapping_statistics(self) -> Dict[str, int]:
        """
        Calcule des statistiques sur les mappings.
        
        Returns:
            Dictionnaire avec les statistiques
        """
        stats = {
            "total_mappings": len(self.cim10_to_cim11),
            "exact_mappings": 0,
            "approximate_mappings": 0,
            "multiple_mappings": 0,
            "no_match": 0,
        }
        
        for mapping in self.cim10_to_cim11.values():
            if mapping.mapping_type == "exact":
                stats["exact_mappings"] += 1
            elif mapping.mapping_type == "approximate":
                stats["approximate_mappings"] += 1
            elif mapping.mapping_type == "multiple":
                stats["multiple_mappings"] += 1
            elif mapping.mapping_type == "no_match":
                stats["no_match"] += 1
        
        return stats
    
    def export_mappings(self, output_file: str, format: str = "yaml") -> None:
        """
        Exporte les mappings vers un fichier.
        
        Args:
            output_file: Chemin du fichier de sortie
            format: Format d'export ("yaml" | "json")
        """
        output_path = self.mappings_dir / output_file
        output_path.parent.mkdir(parents=True, exist_ok=True)
        
        # Préparer les données
        mappings_data = []
        for mapping in self.cim10_to_cim11.values():
            mappings_data.append({
                "cim10_code": mapping.cim10_code,
                "cim10_label": mapping.cim10_label,
                "cim11_codes": mapping.cim11_codes,
                "cim11_labels": mapping.cim11_labels,
                "mapping_type": mapping.mapping_type,
                "notes": mapping.notes
            })
        
        data = {"mappings": mappings_data}
        
        # Écrire le fichier
        with open(output_path, "w", encoding="utf-8") as f:
            if format == "yaml":
                yaml.dump(data, f, allow_unicode=True, default_flow_style=False)
            elif format == "json":
                json.dump(data, f, ensure_ascii=False, indent=2)
            else:
                raise ValueError(f"Format non supporté: {format}")
        
        logger.info(f"Mappings exportés vers {output_path}")
