#!/usr/bin/env python
"""
Script pour charger et indexer tous les référentiels médicaux.

Ce script :
1. Charge et indexe CIM-10 2026 depuis le PDF
2. Convertit/vérifie CCAM V81 → 2025
3. Extrait le Guide Méthodologique MCO 2026
4. Utilise le GPU pour l'indexation FAISS

Usage:
    python scripts/load_referentiels.py
"""

import json
import logging
import sys
from pathlib import Path
from typing import List, Dict

# Ajouter le répertoire parent au path
sys.path.insert(0, str(Path(__file__).parent.parent))

try:
    import pypdf
    PDF_SUPPORT = True
except ImportError:
    PDF_SUPPORT = False
    print("⚠️  pypdf non installé. Installez-le avec: pip install pypdf")
    sys.exit(1)

try:
    import pandas as pd
    EXCEL_SUPPORT = True
except ImportError:
    EXCEL_SUPPORT = False
    print("⚠️  pandas non installé. Installez-le avec: pip install pandas openpyxl")
    sys.exit(1)

from pipeline_mco_pmsi.rag.referentiels_manager import ReferentielsManager

# Configuration du logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


def extract_text_from_pdf(pdf_path: Path) -> str:
    """Extrait le texte d'un fichier PDF."""
    logger.info(f"📄 Extraction du PDF: {pdf_path.name}")
    
    text_parts = []
    try:
        with open(pdf_path, 'rb') as f:
            reader = pypdf.PdfReader(f)
            
            if reader.is_encrypted:
                try:
                    reader.decrypt('')
                except:
                    raise RuntimeError(f"PDF protégé par mot de passe: {pdf_path.name}")
            
            total_pages = len(reader.pages)
            logger.info(f"   {total_pages} pages à traiter...")
            
            for i, page in enumerate(reader.pages, 1):
                if i % 50 == 0:
                    logger.info(f"   Progression: {i}/{total_pages} pages")
                text = page.extract_text()
                if text:
                    text_parts.append(text)
        
        full_text = '\n\n'.join(text_parts)
        logger.info(f"✅ Extraction terminée: {len(full_text)} caractères")
        return full_text
        
    except Exception as e:
        logger.error(f"❌ Erreur extraction PDF: {e}")
        raise


def load_cim10(data_dir: Path, manager: ReferentielsManager) -> bool:
    """Charge et indexe le référentiel CIM-10 2026."""
    logger.info("\n" + "="*60)
    logger.info("🏥 CHARGEMENT CIM-10 2026")
    logger.info("="*60)
    
    pdf_path = Path("cim-10-fr_2026_a_usage_pmsi_version_provisoire_111225.pdf")
    
    if not pdf_path.exists():
        logger.error(f"❌ Fichier CIM-10 introuvable: {pdf_path}")
        return False
    
    try:
        # Extraire le texte du PDF
        text = extract_text_from_pdf(pdf_path)
        
        # Sauvegarder le texte brut
        text_file = data_dir / "cim10_2026_text.txt"
        logger.info(f"💾 Sauvegarde du texte: {text_file}")
        with open(text_file, 'w', encoding='utf-8') as f:
            f.write(text)
        
        # Découper en chunks et indexer
        logger.info("🔪 Découpage en chunks...")
        chunks = manager.chunk_cim10(text, "2026")
        logger.info(f"   {len(chunks)} chunks créés")
        
        # Construire l'index FAISS
        logger.info("🔍 Construction de l'index FAISS...")
        index = manager.build_index(chunks)
        logger.info(f"   Index créé avec {index.dimension} dimensions")
        
        # Sauvegarder les chunks
        chunks_file = data_dir / "cim10_2026_chunks.json"
        logger.info(f"💾 Sauvegarde des chunks: {chunks_file}")
        chunks_data = [chunk.model_dump() for chunk in chunks]
        with open(chunks_file, 'w', encoding='utf-8') as f:
            json.dump(chunks_data, f, ensure_ascii=False, indent=2)
        
        logger.info("✅ CIM-10 2026 chargé et indexé avec succès!")
        return True
        
    except Exception as e:
        logger.error(f"❌ Erreur chargement CIM-10: {e}")
        import traceback
        traceback.print_exc()
        return False


def load_ccam(data_dir: Path, manager: ReferentielsManager) -> bool:
    """Charge et indexe le référentiel CCAM 2025 (V81)."""
    logger.info("\n" + "="*60)
    logger.info("🔧 CHARGEMENT CCAM 2025 (V81)")
    logger.info("="*60)
    
    # Vérifier si les fichiers V81 existent
    v81_chunks = data_dir / "ccam_V81_chunks.json"
    v81_text = data_dir / "ccam_V81_text.txt"
    
    if v81_chunks.exists() and v81_text.exists():
        logger.info("📦 Fichiers CCAM V81 trouvés, conversion en version 2025...")
        
        try:
            # Charger les chunks V81
            with open(v81_chunks, 'r', encoding='utf-8') as f:
                chunks_data = json.load(f)
            
            logger.info(f"   {len(chunks_data)} chunks trouvés")
            
            # Convertir en version 2025
            logger.info("🔄 Conversion V81 → 2025...")
            for chunk in chunks_data:
                chunk['referentiel_version'] = '2025'
                chunk['chunk_id'] = chunk['chunk_id'].replace('V81', '2025')
            
            # Sauvegarder avec le nouveau nom
            chunks_2025 = data_dir / "ccam_2025_chunks.json"
            with open(chunks_2025, 'w', encoding='utf-8') as f:
                json.dump(chunks_data, f, ensure_ascii=False, indent=2)
            
            # Copier le fichier texte
            text_2025 = data_dir / "ccam_2025_text.txt"
            with open(v81_text, 'r', encoding='utf-8') as f:
                text_content = f.read()
            with open(text_2025, 'w', encoding='utf-8') as f:
                f.write(text_content)
            
            # Réindexer avec FAISS
            logger.info("🔍 Construction de l'index FAISS...")
            
            # Recréer les objets Chunk
            from pipeline_mco_pmsi.rag.referentiels_manager import Chunk
            chunks_objects = [Chunk(**chunk) for chunk in chunks_data]
            
            # Construire l'index
            index = manager.build_index(chunks_objects)
            logger.info(f"   Index créé avec {index.dimension} dimensions")
            
            logger.info("✅ CCAM 2025 converti et indexé avec succès!")
            return True
            
        except Exception as e:
            logger.error(f"❌ Erreur conversion CCAM: {e}")
            logger.info("   Tentative de rechargement depuis le fichier Excel...")
    
    # Si conversion échoue ou fichiers absents, charger depuis Excel
    excel_path = Path("CCAM_V81.xls")
    if not excel_path.exists():
        excel_path = data_dir / "CCAM_V81.xls"
    
    if not excel_path.exists():
        logger.error(f"❌ Fichier CCAM introuvable: CCAM_V81.xls")
        return False
    
    try:
        logger.info(f"📊 Lecture du fichier Excel: {excel_path.name}")
        
        # Lire le fichier Excel
        df = pd.read_excel(excel_path)
        logger.info(f"   {len(df)} lignes trouvées")
        
        # Extraire le texte (adapter selon la structure du fichier)
        text_parts = []
        for _, row in df.iterrows():
            # Adapter selon les colonnes du fichier CCAM
            row_text = ' '.join(str(val) for val in row.values if pd.notna(val))
            text_parts.append(row_text)
        
        text = '\n\n'.join(text_parts)
        
        # Sauvegarder le texte
        text_file = data_dir / "ccam_2025_text.txt"
        logger.info(f"💾 Sauvegarde du texte: {text_file}")
        with open(text_file, 'w', encoding='utf-8') as f:
            f.write(text)
        
        # Découper et indexer
        logger.info("🔪 Découpage en chunks...")
        chunks = manager.chunk_ccam(text, "2025")
        logger.info(f"   {len(chunks)} chunks créés")
        
        # Construire l'index FAISS
        logger.info("🔍 Construction de l'index FAISS...")
        index = manager.build_index(chunks)
        logger.info(f"   Index créé avec {index.dimension} dimensions")
        
        # Sauvegarder les chunks
        chunks_file = data_dir / "ccam_2025_chunks.json"
        logger.info(f"💾 Sauvegarde des chunks: {chunks_file}")
        chunks_data = [chunk.model_dump() for chunk in chunks]
        with open(chunks_file, 'w', encoding='utf-8') as f:
            json.dump(chunks_data, f, ensure_ascii=False, indent=2)
        
        logger.info("✅ CCAM 2025 chargé et indexé avec succès!")
        return True
        
    except Exception as e:
        logger.error(f"❌ Erreur chargement CCAM: {e}")
        import traceback
        traceback.print_exc()
        return False


def load_guide_mco(data_dir: Path, manager: ReferentielsManager) -> bool:
    """Charge et indexe le Guide Méthodologique MCO 2026."""
    logger.info("\n" + "="*60)
    logger.info("📚 CHARGEMENT GUIDE MÉTHODOLOGIQUE MCO 2026")
    logger.info("="*60)
    
    pdf_path = Path("guide_methodo_mco_2026_version_provisoire.pdf")
    
    if not pdf_path.exists():
        logger.warning(f"⚠️  Fichier Guide MCO introuvable: {pdf_path}")
        logger.info("   Le système fonctionnera sans le guide (optionnel)")
        return False
    
    try:
        # Extraire le texte du PDF
        text = extract_text_from_pdf(pdf_path)
        
        # Sauvegarder le texte brut
        text_file = data_dir / "guide_mco_2026_text.txt"
        logger.info(f"💾 Sauvegarde du texte: {text_file}")
        with open(text_file, 'w', encoding='utf-8') as f:
            f.write(text)
        
        # Découper en chunks et indexer
        logger.info("🔪 Découpage en chunks...")
        chunks = manager.chunk_guide_mco(text, "2026")
        logger.info(f"   {len(chunks)} chunks créés")
        
        # Construire l'index FAISS
        logger.info("🔍 Construction de l'index FAISS...")
        index = manager.build_index(chunks)
        logger.info(f"   Index créé avec {index.dimension} dimensions")
        
        # Sauvegarder les chunks
        chunks_file = data_dir / "guide_mco_2026_chunks.json"
        logger.info(f"💾 Sauvegarde des chunks: {chunks_file}")
        chunks_data = [chunk.model_dump() for chunk in chunks]
        with open(chunks_file, 'w', encoding='utf-8') as f:
            json.dump(chunks_data, f, ensure_ascii=False, indent=2)
        
        logger.info("✅ Guide MCO 2026 chargé et indexé avec succès!")
        return True
        
    except Exception as e:
        logger.error(f"❌ Erreur chargement Guide MCO: {e}")
        import traceback
        traceback.print_exc()
        return False


def main():
    """Point d'entrée principal."""
    logger.info("\n" + "🚀 "*30)
    logger.info("CHARGEMENT DES RÉFÉRENTIELS MÉDICAUX")
    logger.info("🚀 "*30 + "\n")
    
    # Créer le répertoire de données si nécessaire
    data_dir = Path("data/referentiels")
    data_dir.mkdir(parents=True, exist_ok=True)
    
    # Initialiser le ReferentielsManager
    logger.info(f"📁 Répertoire de données: {data_dir.absolute()}")
    manager = ReferentielsManager(data_dir=data_dir)
    
    # Charger les référentiels
    results = {
        "CIM-10 2026": load_cim10(data_dir, manager),
        "CCAM 2025": load_ccam(data_dir, manager),
        "Guide MCO 2026": load_guide_mco(data_dir, manager),
    }
    
    # Résumé
    logger.info("\n" + "="*60)
    logger.info("📊 RÉSUMÉ DU CHARGEMENT")
    logger.info("="*60)
    
    for name, success in results.items():
        status = "✅ OK" if success else "❌ ÉCHEC"
        logger.info(f"   {name}: {status}")
    
    # Vérifier les fichiers créés
    logger.info("\n📦 Fichiers créés:")
    for file in sorted(data_dir.glob("*_2025_*")) + sorted(data_dir.glob("*_2026_*")):
        size_mb = file.stat().st_size / (1024 * 1024)
        logger.info(f"   {file.name} ({size_mb:.1f} MB)")
    
    # Statut final
    all_success = all(results.values())
    if all_success:
        logger.info("\n🎉 Tous les référentiels ont été chargés avec succès!")
        logger.info("   Le système est prêt à traiter des séjours.")
    else:
        logger.warning("\n⚠️  Certains référentiels n'ont pas pu être chargés.")
        logger.info("   Le système fonctionnera avec les référentiels disponibles.")
    
    return 0 if all_success else 1


if __name__ == "__main__":
    sys.exit(main())
