#!/usr/bin/env python3
"""
Script d'import du référentiel CCAM depuis un fichier Excel.

Ce script:
1. Lit le fichier Excel CCAM_V81.xls
2. Extrait les codes CCAM avec leurs descriptions
3. Convertit en format texte structuré
4. Importe dans le ReferentielsManager
5. Génère les chunks et l'index vectoriel
"""

import argparse
import logging
import sys
from pathlib import Path

# Add src to path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))

# Configuration du logging avant les imports qui l'utilisent
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)

try:
    import pandas as pd
    import openpyxl
    EXCEL_SUPPORT = True
except ImportError:
    EXCEL_SUPPORT = False
    logger.error("pandas ou openpyxl non installé. Installez avec: pip install pandas openpyxl")
    sys.exit(1)

from pipeline_mco_pmsi.rag.referentiels_manager import ReferentielsManager


def extract_ccam_from_excel(excel_path: Path) -> str:
    """
    Extrait le contenu du référentiel CCAM depuis un fichier Excel.
    
    Args:
        excel_path: Chemin vers le fichier Excel CCAM
        
    Returns:
        Texte structuré du référentiel CCAM
    """
    logger.info(f"Lecture du fichier Excel: {excel_path}")
    
    # Utiliser pandas pour lire le fichier Excel (supporte .xls et .xlsx)
    try:
        df = pd.read_excel(excel_path, engine='xlrd')
    except Exception as e:
        logger.warning(f"Échec avec xlrd, tentative avec openpyxl: {e}")
        try:
            df = pd.read_excel(excel_path, engine='openpyxl')
        except Exception as e2:
            logger.error(f"Impossible de lire le fichier Excel: {e2}")
            raise RuntimeError(f"Échec de lecture du fichier Excel: {e2}")
    
    logger.info(f"DataFrame chargé: {len(df)} lignes, {len(df.columns)} colonnes")
    logger.info(f"Colonnes: {list(df.columns)}")
    
    # Structure pour stocker le contenu
    lines = []
    current_chapter = ""
    
    # Analyser la structure des colonnes
    # Adapter selon la structure réelle du fichier CCAM
    col_names = list(df.columns)
    
    # Essayer de détecter les colonnes importantes
    code_col = None
    desc_col = None
    
    for i, col in enumerate(col_names):
        col_lower = str(col).lower()
        if 'code' in col_lower and code_col is None:
            code_col = i
        elif any(keyword in col_lower for keyword in ['libellé', 'libelle', 'description', 'texte']) and desc_col is None:
            desc_col = i
    
    # Si pas trouvé, utiliser les premières colonnes par défaut
    if code_col is None:
        code_col = 0
        logger.warning("Colonne 'code' non détectée, utilisation de la colonne 0")
    if desc_col is None:
        desc_col = 2 if len(col_names) > 2 else 1
        logger.warning(f"Colonne 'description' non détectée, utilisation de la colonne {desc_col}")
    
    logger.info(f"Colonnes utilisées: code={code_col}, description={desc_col}")
    
    # Parcourir les lignes
    for idx, row in df.iterrows():
        # Ignorer les lignes vides
        if row.isna().all():
            continue
        
        code = str(row.iloc[code_col]).strip() if pd.notna(row.iloc[code_col]) else ""
        text = str(row.iloc[desc_col]).strip() if pd.notna(row.iloc[desc_col]) and desc_col < len(row) else ""
        
        # Nettoyer les valeurs NaN
        if code == "nan":
            code = ""
        if text == "nan":
            text = ""
        
        # Ligne d'en-tête (première ligne)
        if idx == 0 and text and not code:
            lines.append(f"# RÉFÉRENTIEL CCAM")
            lines.append("")
            continue
        
        # Chapitre (numéro seul dans la colonne code)
        if code and code.replace(".", "").replace(",", "").isdigit() and text:
            current_chapter = text
            lines.append(f"\n## CHAPITRE {code}: {text}")
            lines.append("")
            continue
        
        # Note ou exclusion (pas de code, mais du texte)
        if not code and text:
            if "exclusion" in text.lower():
                lines.append(f"**Exclusion**: {text}")
            elif text.startswith("Par ") or text.startswith("Note"):
                lines.append(f"**Note**: {text}")
            else:
                lines.append(text)
            lines.append("")
            continue
        
        # Code CCAM (format: XXXX000 ou XXXX000+XXX pour extensions ATIH)
        # Accepter aussi les codes avec extensions
        if code and len(code) >= 7:
            # Vérifier le format de base (4 lettres + 3 chiffres)
            base_code = code[:7]
            if len(base_code) == 7 and base_code[:4].isalpha() and base_code[4:].isdigit():
                # Extraire les métadonnées supplémentaires si disponibles
                activite = ""
                phase = ""
                
                if len(row) > 3 and pd.notna(row.iloc[3]):
                    activite = str(row.iloc[3]).strip()
                if len(row) > 4 and pd.notna(row.iloc[4]):
                    phase = str(row.iloc[4]).strip()
                
                # Formater l'entrée CCAM
                lines.append(f"### {code}")
                if text:
                    lines.append(f"**Description**: {text}")
                
                if activite and activite != "nan":
                    lines.append(f"**Activité**: {activite}")
                if phase and phase != "nan":
                    lines.append(f"**Phase**: {phase}")
                
                # Ajouter le chapitre pour contexte
                if current_chapter:
                    lines.append(f"**Chapitre**: {current_chapter}")
                
                # Détecter les extensions ATIH (format +XXX)
                if "+" in code:
                    extension = code.split("+")[1] if len(code.split("+")) > 1 else ""
                    if extension:
                        lines.append(f"**Extension ATIH**: +{extension}")
                
                lines.append("")
    
    full_text = "\n".join(lines)
    logger.info(f"Extraction terminée: {len(lines)} lignes, {len(full_text)} caractères")
    
    return full_text


def main():
    """Point d'entrée principal du script."""
    parser = argparse.ArgumentParser(
        description="Import du référentiel CCAM dans le système"
    )
    parser.add_argument(
        "--excel-file",
        type=Path,
        default=Path("data/referentiels/CCAM_V81.xls"),
        help="Chemin vers le fichier Excel CCAM (défaut: data/referentiels/CCAM_V81.xls)"
    )
    parser.add_argument(
        "--version",
        type=str,
        default="V81",
        help="Version du référentiel CCAM (défaut: V81)"
    )
    parser.add_argument(
        "--data-dir",
        type=Path,
        default=Path("data/referentiels"),
        help="Répertoire de stockage des référentiels (défaut: data/referentiels)"
    )
    parser.add_argument(
        "--skip-indexing",
        action="store_true",
        help="Ne pas créer l'index vectoriel (seulement import et chunking)"
    )
    
    args = parser.parse_args()
    
    # Vérifier que le fichier existe
    if not args.excel_file.exists():
        logger.error(f"Fichier Excel introuvable: {args.excel_file}")
        sys.exit(1)
    
    try:
        # 1. Extraire le contenu du fichier Excel
        logger.info("=" * 60)
        logger.info("ÉTAPE 1: Extraction du contenu Excel")
        logger.info("=" * 60)
        ccam_text = extract_ccam_from_excel(args.excel_file)
        
        # Sauvegarder le texte extrait
        text_output_path = args.data_dir / f"ccam_{args.version}_extracted.txt"
        with open(text_output_path, "w", encoding="utf-8") as f:
            f.write(ccam_text)
        logger.info(f"Texte extrait sauvegardé dans: {text_output_path}")
        
        # 2. Importer dans le ReferentielsManager
        logger.info("")
        logger.info("=" * 60)
        logger.info("ÉTAPE 2: Import dans ReferentielsManager")
        logger.info("=" * 60)
        
        manager = ReferentielsManager(data_dir=args.data_dir)
        
        # Créer un fichier PDF temporaire pour l'import
        # (le ReferentielsManager attend un PDF, mais on va contourner ça)
        # Pour l'instant, on va directement sauvegarder le texte et créer la version
        
        # Sauvegarder le texte pour chunking
        text_file_path = args.data_dir / f"ccam_{args.version}_text.txt"
        with open(text_file_path, "w", encoding="utf-8") as f:
            f.write(ccam_text)
        
        # Créer manuellement la version du référentiel
        import hashlib
        from datetime import datetime
        from pipeline_mco_pmsi.models.metadata import ReferentielVersion
        
        file_hash = hashlib.sha256(ccam_text.encode()).hexdigest()
        placeholder_hash = "0" * 64
        
        referentiel_version = ReferentielVersion(
            type="ccam",
            version=args.version,
            import_date=datetime.now(),
            file_hash=file_hash,
            chunk_count=0,
            index_hash=placeholder_hash,
        )
        
        logger.info(f"Référentiel CCAM {args.version} créé avec hash: {file_hash[:16]}...")
        
        # 3. Chunking
        logger.info("")
        logger.info("=" * 60)
        logger.info("ÉTAPE 3: Chunking du référentiel")
        logger.info("=" * 60)
        
        chunks = manager.chunk_referentiel(referentiel_version)
        logger.info(f"Chunking terminé: {len(chunks)} chunks créés")
        
        # Créer une nouvelle version avec le chunk_count mis à jour
        referentiel_version = ReferentielVersion(
            type=referentiel_version.type,
            version=referentiel_version.version,
            import_date=referentiel_version.import_date,
            file_hash=referentiel_version.file_hash,
            chunk_count=len(chunks),
            index_hash=referentiel_version.index_hash,
        )
        
        # 4. Indexation (optionnel)
        if not args.skip_indexing:
            logger.info("")
            logger.info("=" * 60)
            logger.info("ÉTAPE 4: Construction de l'index vectoriel")
            logger.info("=" * 60)
            
            vector_index = manager.build_index(chunks)
            logger.info(f"Index vectoriel créé:")
            logger.info(f"  - Hash: {vector_index.index_hash[:16]}...")
            logger.info(f"  - Dimension: {vector_index.dimension}")
            logger.info(f"  - Nombre de vecteurs: {vector_index.num_vectors}")
            logger.info(f"  - Type d'index: {vector_index.index_type}")
            
            # Créer une nouvelle version avec l'index_hash mis à jour
            referentiel_version = ReferentielVersion(
                type=referentiel_version.type,
                version=referentiel_version.version,
                import_date=referentiel_version.import_date,
                file_hash=referentiel_version.file_hash,
                chunk_count=referentiel_version.chunk_count,
                index_hash=vector_index.index_hash,
            )
        else:
            logger.info("")
            logger.info("Indexation ignorée (--skip-indexing)")
        
        # 5. Résumé
        logger.info("")
        logger.info("=" * 60)
        logger.info("IMPORT TERMINÉ AVEC SUCCÈS")
        logger.info("=" * 60)
        logger.info(f"Référentiel: CCAM {args.version}")
        logger.info(f"Hash du fichier: {referentiel_version.file_hash[:16]}...")
        logger.info(f"Nombre de chunks: {referentiel_version.chunk_count}")
        if not args.skip_indexing:
            logger.info(f"Hash de l'index: {referentiel_version.index_hash[:16]}...")
        logger.info(f"Date d'import: {referentiel_version.import_date}")
        
    except Exception as e:
        logger.error(f"Erreur lors de l'import: {e}", exc_info=True)
        sys.exit(1)


if __name__ == "__main__":
    main()
