"""
Tests unitaires pour le ReferentielsManager.

Ces tests vérifient l'import, le hashing et le chunking des référentiels ATIH.
"""

import hashlib
import tempfile
from datetime import datetime
from pathlib import Path

import pytest

from pipeline_mco_pmsi.rag import ReferentielsManager


@pytest.fixture
def temp_data_dir():
    """Crée un répertoire temporaire pour les tests."""
    with tempfile.TemporaryDirectory() as tmpdir:
        yield Path(tmpdir)


@pytest.fixture
def sample_pdf():
    """Crée un PDF de test simple."""
    from pypdf import PdfWriter
    
    with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp:
        writer = PdfWriter()
        writer.add_blank_page(width=200, height=200)
        writer.write(tmp)
        tmp_path = Path(tmp.name)
    
    yield tmp_path
    
    # Cleanup
    if tmp_path.exists():
        tmp_path.unlink()


class TestReferentielsManagerInit:
    """Tests d'initialisation du ReferentielsManager."""

    def test_init_creates_data_dir(self, temp_data_dir):
        """Test que l'initialisation crée le répertoire de données."""
        data_dir = temp_data_dir / "referentiels"
        manager = ReferentielsManager(data_dir=data_dir)
        
        assert data_dir.exists()
        assert manager.data_dir == data_dir
        assert manager.embedding_model_name == "camembert-bio"

    def test_init_with_custom_embedding_model(self, temp_data_dir):
        """Test l'initialisation avec un modèle d'embeddings personnalisé."""
        manager = ReferentielsManager(
            data_dir=temp_data_dir,
            embedding_model="drbert"
        )
        
        assert manager.embedding_model_name == "drbert"


class TestImportReferentiel:
    """Tests d'import de référentiels."""

    def test_import_referentiel_invalid_type(self, temp_data_dir, sample_pdf):
        """Test que l'import rejette un type de référentiel invalide."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        with pytest.raises(ValueError, match="Type de référentiel invalide"):
            manager.import_referentiel(
                file_path=str(sample_pdf),
                referentiel_type="invalid_type",
                version="2026"
            )

    def test_import_referentiel_file_not_found(self, temp_data_dir):
        """Test que l'import échoue si le fichier n'existe pas."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        with pytest.raises(FileNotFoundError):
            manager.import_referentiel(
                file_path="/nonexistent/file.pdf",
                referentiel_type="cim10",
                version="2026"
            )

    def test_import_referentiel_generates_hash(self, temp_data_dir, sample_pdf):
        """Test que l'import génère un hash SHA-256."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Calculer le hash attendu
        with open(sample_pdf, "rb") as f:
            expected_hash = hashlib.sha256(f.read()).hexdigest()
        
        result = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="cim10",
            version="2026"
        )
        
        assert result.file_hash == expected_hash
        assert len(result.file_hash) == 64  # SHA-256 = 64 caractères hex

    def test_import_referentiel_creates_version(self, temp_data_dir, sample_pdf):
        """Test que l'import crée une ReferentielVersion correcte."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        result = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="guide_mco",
            version="2026"
        )
        
        assert result.type == "guide_mco"
        assert result.version == "2026"
        assert isinstance(result.import_date, datetime)
        assert result.file_hash is not None
        assert len(result.file_hash) == 64

    def test_import_referentiel_saves_text(self, temp_data_dir, sample_pdf):
        """Test que l'import sauvegarde le texte extrait."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="ccam",
            version="2025"
        )
        
        text_file = temp_data_dir / "ccam_2025_text.txt"
        assert text_file.exists()

    def test_import_referentiel_caches_version(self, temp_data_dir, sample_pdf):
        """Test que l'import met en cache la version."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        result = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="cim10",
            version="2026"
        )
        
        # Vérifier que la version est dans le cache
        cached_version = manager.get_version_info("cim10")
        assert cached_version is not None
        assert cached_version.type == "cim10"
        assert cached_version.version == "2026"
        assert cached_version.file_hash == result.file_hash


class TestGetVersionInfo:
    """Tests de récupération des informations de version."""

    def test_get_version_info_not_found(self, temp_data_dir):
        """Test que get_version_info retourne None si non trouvé."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        result = manager.get_version_info("cim10")
        assert result is None

    def test_get_version_info_returns_cached(self, temp_data_dir, sample_pdf):
        """Test que get_version_info retourne la version en cache."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        imported = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="guide_mco",
            version="2026"
        )
        
        result = manager.get_version_info("guide_mco")
        assert result is not None
        assert result.type == imported.type
        assert result.version == imported.version
        assert result.file_hash == imported.file_hash


class TestChunkReferentiel:
    """Tests de chunking des référentiels."""

    def test_chunk_referentiel_guide_mco(self, temp_data_dir, sample_pdf):
        """Test le chunking du Guide MCO."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Import d'abord
        ref_version = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="guide_mco",
            version="2026"
        )
        
        # Chunking
        chunks = manager.chunk_referentiel(ref_version)
        
        assert len(chunks) > 0
        for chunk in chunks:
            assert chunk.referentiel_type == "guide_mco"
            assert chunk.referentiel_version == "2026"
            assert chunk.content is not None
            assert chunk.chunk_id.startswith("guide_mco_2026_")

    def test_chunk_referentiel_cim10(self, temp_data_dir, sample_pdf):
        """Test le chunking de la CIM-10."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        ref_version = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="cim10",
            version="2026"
        )
        
        chunks = manager.chunk_referentiel(ref_version)
        
        assert len(chunks) > 0
        for chunk in chunks:
            assert chunk.referentiel_type == "cim10"
            assert chunk.chunk_id.startswith("cim10_2026_")

    def test_chunk_referentiel_ccam(self, temp_data_dir, sample_pdf):
        """Test le chunking de la CCAM."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        ref_version = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="ccam",
            version="2025"
        )
        
        chunks = manager.chunk_referentiel(ref_version)
        
        assert len(chunks) > 0
        for chunk in chunks:
            assert chunk.referentiel_type == "ccam"
            assert chunk.chunk_id.startswith("ccam_2025_")

    def test_chunk_referentiel_file_not_found(self, temp_data_dir):
        """Test que le chunking échoue si le fichier texte n'existe pas."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        from pipeline_mco_pmsi.models.metadata import ReferentielVersion
        
        # Créer une version sans avoir importé le fichier
        fake_version = ReferentielVersion(
            type="cim10",
            version="2026",
            import_date=datetime.now(),
            file_hash="a" * 64,
            chunk_count=0,
            index_hash="0" * 64  # Placeholder hash
        )
        
        with pytest.raises(RuntimeError, match="Fichier texte du référentiel introuvable"):
            manager.chunk_referentiel(fake_version)


class TestChunkGuideMCO:
    """Tests spécifiques pour le chunking du Guide MCO."""
    
    def test_chunk_guide_mco_preserves_rules(self, temp_data_dir):
        """Test que le chunking préserve les règles complètes."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Créer un texte de test avec des règles
        test_text = """CHAPITRE 1 - Le recueil d'information

1.1 Règles générales

Règle 1: Le diagnostic principal (DP) est la pathologie ayant motivé l'admission.

Critère d'éligibilité:
- Le DP doit être documenté dans le dossier médical
- Le DP doit être codé selon la CIM-10

Exclusion: Les antécédents ne peuvent pas être DP.

1.2 Règles spécifiques

Règle 2: Les diagnostics associés significatifs (DAS) sont les comorbidités.
"""
        
        # Sauvegarder le texte
        text_file = temp_data_dir / "guide_mco_2026_text.txt"
        with open(text_file, "w", encoding="utf-8") as f:
            f.write(test_text)
        
        chunks = manager.chunk_guide_mco(test_text, "2026")
        
        # Vérifier qu'on a des chunks
        assert len(chunks) > 0
        
        # Vérifier que les métadonnées contiennent la section
        for chunk in chunks:
            assert "section" in chunk.metadata
            assert chunk.metadata["chunk_type"] == "section"
        
        # Vérifier qu'aucune règle n'est coupée au milieu
        # (une règle commence par "Règle" et se termine avant la prochaine règle ou section)
        full_content = "\n".join([c.content for c in chunks])
        assert "Règle 1:" in full_content
        assert "Règle 2:" in full_content
        assert "Exclusion:" in full_content
    
    def test_chunk_guide_mco_respects_size_limits(self, temp_data_dir):
        """Test que les chunks respectent les limites de taille."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Créer un texte long
        test_text = "CHAPITRE 1\n\n" + ("Paragraphe de test. " * 500)
        
        chunks = manager.chunk_guide_mco(test_text, "2026")
        
        # Vérifier que les chunks ne dépassent pas la taille max
        for chunk in chunks:
            assert len(chunk.content) <= 4096  # max_chunk_size
    
    def test_chunk_guide_mco_creates_overlap(self, temp_data_dir):
        """Test que le chunking crée un overlap entre chunks."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Créer un texte avec plusieurs sections
        test_text = """CHAPITRE 1

Section 1.1
""" + ("Contenu de la section 1.1. " * 200) + """

Section 1.2
""" + ("Contenu de la section 1.2. " * 200)
        
        chunks = manager.chunk_guide_mco(test_text, "2026")
        
        # Si on a plusieurs chunks, vérifier qu'il y a un overlap
        if len(chunks) > 1:
            # Le dernier contenu du chunk N devrait apparaître au début du chunk N+1
            for i in range(len(chunks) - 1):
                chunk_n_end = chunks[i].content[-200:]  # Derniers 200 caractères
                chunk_n1_start = chunks[i + 1].content[:400]  # Premiers 400 caractères
                
                # Vérifier qu'il y a un overlap (au moins quelques mots en commun)
                # On cherche des mots de plus de 5 caractères
                words_n = [w for w in chunk_n_end.split() if len(w) > 5]
                if words_n:
                    # Au moins un mot devrait être dans le chunk suivant
                    assert any(word in chunk_n1_start for word in words_n[:5])


class TestChunkCIM10:
    """Tests spécifiques pour le chunking de la CIM-10."""
    
    def test_chunk_cim10_preserves_notes(self, temp_data_dir):
        """Test que le chunking préserve les notes d'inclusion/exclusion."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Créer un texte de test avec des codes et notes
        test_text = """CHAPITRE I - Maladies infectieuses

A00-A09 Maladies intestinales infectieuses

A00 Choléra
A00.0 Choléra dû à Vibrio cholerae 01, biovar cholerae
A00.1 Choléra dû à Vibrio cholerae 01, biovar El Tor
A00.9 Choléra, sans précision

Inclus: infection à Vibrio cholerae
Exclut: intoxication alimentaire (A05.-)

A01 Fièvres typhoïde et paratyphoïde
A01.0 Fièvre typhoïde

Note: La fièvre typhoïde est causée par Salmonella typhi.
Comprend: infection à Salmonella typhi
"""
        
        # Sauvegarder le texte
        text_file = temp_data_dir / "cim10_2026_text.txt"
        with open(text_file, "w", encoding="utf-8") as f:
            f.write(test_text)
        
        chunks = manager.chunk_cim10(test_text, "2026")
        
        # Vérifier qu'on a des chunks
        assert len(chunks) > 0
        
        # Vérifier que les métadonnées contiennent le chapitre
        for chunk in chunks:
            assert "chapter" in chunk.metadata
            assert chunk.metadata["chunk_type"] == "code_block"
        
        # Vérifier que les notes ne sont pas coupées
        full_content = "\n".join([c.content for c in chunks])
        assert "Inclus:" in full_content
        assert "Exclut:" in full_content
        assert "Note:" in full_content
    
    def test_chunk_cim10_respects_size_limits(self, temp_data_dir):
        """Test que les chunks respectent les limites de taille."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Créer un texte long
        test_text = "CHAPITRE I\n\n" + ("A00 Code de test\n" * 300)
        
        chunks = manager.chunk_cim10(test_text, "2026")
        
        # Vérifier que les chunks ne dépassent pas la taille max
        for chunk in chunks:
            assert len(chunk.content) <= 4096  # max_chunk_size
    
    def test_chunk_cim10_does_not_cut_note_blocks(self, temp_data_dir):
        """Test que les blocs de notes ne sont jamais coupés."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Créer un texte avec un long bloc de notes
        test_text = """A00 Choléra

Inclus:
- infection à Vibrio cholerae
- choléra classique
- choléra El Tor
- choléra asiatique
- choléra épidémique

Exclut:
- intoxication alimentaire (A05.-)
- gastro-entérite non infectieuse (K52.-)

A01 Fièvre typhoïde
"""
        
        chunks = manager.chunk_cim10(test_text, "2026")
        
        # Vérifier que chaque chunk contient soit le bloc complet, soit rien du bloc
        for chunk in chunks:
            if "Inclus:" in chunk.content:
                # Si le chunk contient "Inclus:", il doit contenir toute la liste
                assert "- infection à Vibrio cholerae" in chunk.content
                assert "- choléra épidémique" in chunk.content


class TestChunkCCAM:
    """Tests spécifiques pour le chunking de la CCAM."""
    
    def test_chunk_ccam_preserves_extensions(self, temp_data_dir):
        """Test que le chunking préserve les extensions ATIH."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Créer un texte de test avec des codes CCAM et extensions
        test_text = """CHAPITRE 1 - Actes diagnostiques

SECTION 1.1 - Imagerie

YYYY001 Radiographie du thorax
Description: Radiographie standard du thorax de face et de profil

Extensions ATIH:
+ABC Extension pour urgence
+DEF Extension pour patient hospitalisé
+GHI Extension pour acte itératif

Note technique: Cet acte nécessite une prescription médicale.
Condition d'application: Patient en position debout ou allongé.

YYYY002 Scanner thoracique
Description: Tomodensitométrie du thorax avec injection
"""
        
        # Sauvegarder le texte
        text_file = temp_data_dir / "ccam_2025_text.txt"
        with open(text_file, "w", encoding="utf-8") as f:
            f.write(test_text)
        
        chunks = manager.chunk_ccam(test_text, "2025")
        
        # Vérifier qu'on a des chunks
        assert len(chunks) > 0
        
        # Vérifier que les métadonnées contiennent la section
        for chunk in chunks:
            assert "section" in chunk.metadata
            assert chunk.metadata["chunk_type"] == "acte"
        
        # Vérifier que les extensions ne sont pas coupées
        full_content = "\n".join([c.content for c in chunks])
        assert "Extensions ATIH:" in full_content
        assert "+ABC" in full_content
        assert "+DEF" in full_content
        assert "+GHI" in full_content
    
    def test_chunk_ccam_respects_size_limits(self, temp_data_dir):
        """Test que les chunks respectent les limites de taille."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Créer un texte long
        test_text = "CHAPITRE 1\n\n" + ("YYYY001 Acte de test\n" * 300)
        
        chunks = manager.chunk_ccam(test_text, "2025")
        
        # Vérifier que les chunks ne dépassent pas la taille max
        for chunk in chunks:
            assert len(chunk.content) <= 4096  # max_chunk_size
    
    def test_chunk_ccam_does_not_cut_technical_notes(self, temp_data_dir):
        """Test que les notes techniques ne sont jamais coupées."""
        manager = ReferentielsManager(data_dir=temp_data_dir)
        
        # Créer un texte avec une longue note technique
        test_text = """YYYY001 Acte chirurgical

Note technique:
Cet acte nécessite:
- Une anesthésie générale
- Un plateau technique complet
- Une équipe chirurgicale de 3 personnes minimum
- Un contrôle radiologique per-opératoire
- Une surveillance post-opératoire de 24h

Condition d'application: Patient à jeun depuis 6h.

YYYY002 Autre acte
"""
        
        chunks = manager.chunk_ccam(test_text, "2025")
        
        # Vérifier que chaque chunk contient soit la note complète, soit rien de la note
        for chunk in chunks:
            if "Note technique:" in chunk.content:
                # Si le chunk contient "Note technique:", il doit contenir toute la note
                assert "- Une anesthésie générale" in chunk.content
                assert "- Une surveillance post-opératoire de 24h" in chunk.content


class TestBuildIndex:
    """Tests de construction d'index vectoriel."""

    def test_build_index_empty_chunks(self, temp_data_dir):
        """Test que build_index rejette une liste vide de chunks."""
        manager = ReferentielsManager(data_dir=temp_data_dir)

        with pytest.raises(ValueError, match="La liste de chunks ne peut pas être vide"):
            manager.build_index([])

    def test_build_index_creates_vector_index(self, temp_data_dir, sample_pdf):
        """Test que build_index crée un index vectoriel."""
        manager = ReferentielsManager(data_dir=temp_data_dir)

        # Import et chunking
        ref_version = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="cim10",
            version="2026"
        )
        chunks = manager.chunk_referentiel(ref_version)

        # Construction de l'index
        vector_index = manager.build_index(chunks)

        # Vérifications
        assert vector_index.index_hash is not None
        assert len(vector_index.index_hash) == 64  # SHA-256
        assert vector_index.dimension > 0
        assert vector_index.num_vectors == len(chunks)
        assert vector_index.index_type == "HNSW"
        assert isinstance(vector_index.created_at, datetime)

    def test_build_index_saves_to_disk(self, temp_data_dir, sample_pdf):
        """Test que build_index sauvegarde l'index sur disque."""
        manager = ReferentielsManager(data_dir=temp_data_dir)

        # Import et chunking
        ref_version = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="guide_mco",
            version="2026"
        )
        chunks = manager.chunk_referentiel(ref_version)

        # Construction de l'index
        manager.build_index(chunks)

        # Vérifier que le fichier d'index existe
        index_file = temp_data_dir / "guide_mco_2026_index.faiss"
        assert index_file.exists()

        # Vérifier que le fichier de chunks existe
        chunks_file = temp_data_dir / "guide_mco_2026_chunks.json"
        assert chunks_file.exists()


class TestRebuildIndex:
    """Tests de reconstruction d'index après mise à jour."""

    def test_rebuild_index_with_code_mapper(self, temp_data_dir, sample_pdf):
        """Test la reconstruction d'index avec code mapper."""
        from pipeline_mco_pmsi.referentiels import CodeMapper
        from pipeline_mco_pmsi.referentiels.code_mapper import CodeMapping
        from pipeline_mco_pmsi.models.metadata import ReferentielVersion
        from datetime import datetime

        manager = ReferentielsManager(data_dir=temp_data_dir)
        code_mapper = CodeMapper(mappings_dir=temp_data_dir / "mappings")

        # Ajouter un mapping de test
        mapping = CodeMapping(
            obsolete_code="A00.0",
            current_code="A00.1",
            obsolete_label="Ancien code",
            current_label="Nouveau code",
            effective_date=datetime.now(),
            reason="obsolete"
        )
        code_mapper.add_mapping(mapping, "cim10")

        # Import initial
        ref_version = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="cim10",
            version="2026"
        )

        # Chunking et indexation initiale
        chunks = manager.chunk_referentiel(ref_version)
        initial_index = manager.build_index(chunks)

        # Mise à jour du référentiel version dans le cache
        # Créer une nouvelle instance car ReferentielVersion est frozen
        updated_ref_version = ReferentielVersion(
            type=ref_version.type,
            version=ref_version.version,
            import_date=ref_version.import_date,
            file_hash=ref_version.file_hash,
            chunk_count=len(chunks),
            index_hash=initial_index.index_hash
        )
        manager._versions_cache[f"cim10_2026"] = updated_ref_version

        # Reconstruction avec code mapper
        rebuilt_index = manager.rebuild_index("cim10", "2026", code_mapper=code_mapper)

        # Vérifications
        assert rebuilt_index.index_hash is not None
        assert rebuilt_index.num_vectors > 0

        # Le hash devrait être différent car le contenu a changé
        # (même si dans ce test le PDF est vide, la logique est testée)
        assert rebuilt_index.index_hash is not None



    def test_rebuild_index_with_code_mapper(self, temp_data_dir, sample_pdf):
        """Test la reconstruction d'index avec code mapper."""
        from pipeline_mco_pmsi.referentiels import CodeMapper
        from datetime import datetime

        manager = ReferentielsManager(data_dir=temp_data_dir)
        code_mapper = CodeMapper(mappings_dir=temp_data_dir / "mappings")

        # Ajouter un mapping de test
        from pipeline_mco_pmsi.referentiels.code_mapper import CodeMapping
        mapping = CodeMapping(
            obsolete_code="A00.0",
            current_code="A00.1",
            obsolete_label="Ancien code",
            current_label="Nouveau code",
            effective_date=datetime.now(),
            reason="obsolete"
        )
        code_mapper.add_mapping(mapping, "cim10")

        # Import initial
        ref_version = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="cim10",
            version="2026"
        )

        # Chunking et indexation initiale
        chunks = manager.chunk_referentiel(ref_version)
        initial_index = manager.build_index(chunks)

        # Mise à jour du référentiel version dans le cache
        # Créer une nouvelle instance car ReferentielVersion est frozen
        from pipeline_mco_pmsi.models.metadata import ReferentielVersion
        updated_ref_version = ReferentielVersion(
            type=ref_version.type,
            version=ref_version.version,
            import_date=ref_version.import_date,
            file_hash=ref_version.file_hash,
            chunk_count=len(chunks),
            index_hash=initial_index.index_hash
        )
        manager._versions_cache[f"cim10_2026"] = updated_ref_version

        # Reconstruction avec code mapper
        rebuilt_index = manager.rebuild_index("cim10", "2026", code_mapper=code_mapper)

        # Vérifications
        assert rebuilt_index.index_hash is not None
        assert rebuilt_index.num_vectors > 0

        # Le hash devrait être différent car le contenu a changé
        # (même si dans ce test le PDF est vide, la logique est testée)
        assert rebuilt_index.index_hash is not None

    def test_rebuild_index_referentiel_not_found(self, temp_data_dir):
        """Test que rebuild_index échoue si le référentiel n'est pas trouvé."""
        manager = ReferentielsManager(data_dir=temp_data_dir)

        with pytest.raises(RuntimeError, match="Version du référentiel .* non trouvée"):
            manager.rebuild_index("cim10", "2026")

    def test_rebuild_index_text_file_not_found(self, temp_data_dir):
        """Test que rebuild_index échoue si le fichier texte n'existe pas."""
        from pipeline_mco_pmsi.models.metadata import ReferentielVersion

        manager = ReferentielsManager(data_dir=temp_data_dir)

        # Créer une version sans fichier texte
        fake_version = ReferentielVersion(
            type="cim10",
            version="2026",
            import_date=datetime.now(),
            file_hash="a" * 64,
            chunk_count=0,
            index_hash="0" * 64
        )
        manager._versions_cache["cim10_2026"] = fake_version

        with pytest.raises(RuntimeError, match="Fichier texte du référentiel introuvable"):
            manager.rebuild_index("cim10", "2026")

    def test_rebuild_index_updates_metadata(self, temp_data_dir, sample_pdf):
        """Test que rebuild_index met à jour les métadonnées de version."""
        from pipeline_mco_pmsi.models.metadata import ReferentielVersion

        manager = ReferentielsManager(data_dir=temp_data_dir)

        # Import initial
        ref_version = manager.import_referentiel(
            file_path=str(sample_pdf),
            referentiel_type="ccam",
            version="2025"
        )

        # Chunking et indexation initiale
        chunks = manager.chunk_referentiel(ref_version)
        initial_index = manager.build_index(chunks)

        # Mise à jour du référentiel version dans le cache
        # Créer une nouvelle instance car ReferentielVersion est frozen
        updated_ref_version = ReferentielVersion(
            type=ref_version.type,
            version=ref_version.version,
            import_date=ref_version.import_date,
            file_hash=ref_version.file_hash,
            chunk_count=len(chunks),
            index_hash=initial_index.index_hash
        )
        manager._versions_cache[f"ccam_2025"] = updated_ref_version

        # Sauvegarder les valeurs initiales
        initial_hash = updated_ref_version.index_hash
        initial_count = updated_ref_version.chunk_count

        # Reconstruction
        rebuilt_index = manager.rebuild_index("ccam", "2025")

        # Vérifier que les métadonnées ont été mises à jour
        updated_version = manager.get_version_info("ccam")
        assert updated_version.index_hash == rebuilt_index.index_hash
        assert updated_version.chunk_count == rebuilt_index.num_vectors

        # Les valeurs devraient être cohérentes
        assert updated_version.index_hash is not None
        assert updated_version.chunk_count > 0



class TestApplyCodeMappings:
    """Tests d'application des mappings de codes."""

    def test_apply_code_mappings_cim10(self, temp_data_dir):
        """Test l'application des mappings pour CIM-10."""
        from pipeline_mco_pmsi.referentiels import CodeMapper
        from pipeline_mco_pmsi.referentiels.code_mapper import CodeMapping
        from datetime import datetime

        manager = ReferentielsManager(data_dir=temp_data_dir)
        code_mapper = CodeMapper()

        # Ajouter un mapping
        mapping = CodeMapping(
            obsolete_code="A00.0",
            current_code="A00.9",
            obsolete_label="Ancien",
            current_label="Nouveau",
            effective_date=datetime.now(),
            reason="obsolete"
        )
        code_mapper.add_mapping(mapping, "cim10")

        # Texte avec code obsolète
        text = """CHAPITRE I

A00.0 Choléra ancien
A00.1 Choléra actuel
A00.9 Choléra sans précision
"""

        # Appliquer les mappings
        updated_text = manager._apply_code_mappings(text, "cim10", code_mapper)

        # Vérifier que le code obsolète a été remplacé
        assert "A00.9 Choléra ancien" in updated_text
        assert "A00.1 Choléra actuel" in updated_text
        # Le code A00.0 ne devrait plus apparaître seul (remplacé par A00.9)
        import re
        # Compter les occurrences de A00.0 comme code (pas dans A00.01 par exemple)
        a00_0_count = len(re.findall(r'\bA00\.0\b', updated_text))
        assert a00_0_count == 0

    def test_apply_code_mappings_ccam(self, temp_data_dir):
        """Test l'application des mappings pour CCAM."""
        from pipeline_mco_pmsi.referentiels import CodeMapper
        from pipeline_mco_pmsi.referentiels.code_mapper import CodeMapping
        from datetime import datetime

        manager = ReferentielsManager(data_dir=temp_data_dir)
        code_mapper = CodeMapper()

        # Ajouter un mapping
        mapping = CodeMapping(
            obsolete_code="YYYY001",
            current_code="YYYY002",
            obsolete_label="Ancien acte",
            current_label="Nouvel acte",
            effective_date=datetime.now(),
            reason="merged"
        )
        code_mapper.add_mapping(mapping, "ccam")

        # Texte avec code obsolète
        text = """CHAPITRE 1

YYYY001 Acte ancien
YYYY002 Acte actuel
YYYY003 Autre acte
"""

        # Appliquer les mappings
        updated_text = manager._apply_code_mappings(text, "ccam", code_mapper)

        # Vérifier que le code obsolète a été remplacé
        assert "YYYY002 Acte ancien" in updated_text
        assert "YYYY002 Acte actuel" in updated_text
        assert "YYYY003 Autre acte" in updated_text
        # Le code YYYY001 ne devrait plus apparaître
        assert "YYYY001" not in updated_text

    def test_apply_code_mappings_with_aliases(self, temp_data_dir):
        """Test l'application des mappings avec aliases."""
        from pipeline_mco_pmsi.referentiels import CodeMapper

        manager = ReferentielsManager(data_dir=temp_data_dir)
        code_mapper = CodeMapper()

        # Ajouter un alias
        code_mapper.add_alias("A00.X", "A00.9", "cim10")

        # Texte avec alias
        text = """A00.X Choléra (alias)
A00.9 Choléra sans précision
"""

        # Appliquer les mappings
        updated_text = manager._apply_code_mappings(text, "cim10", code_mapper)

        # Vérifier que l'alias a été résolu
        assert "A00.9 Choléra (alias)" in updated_text
        assert "A00.X" not in updated_text

    def test_apply_code_mappings_guide_mco_unchanged(self, temp_data_dir):
        """Test que les mappings ne modifient pas le guide MCO."""
        from pipeline_mco_pmsi.referentiels import CodeMapper

        manager = ReferentielsManager(data_dir=temp_data_dir)
        code_mapper = CodeMapper()

        # Texte du guide
        text = """CHAPITRE 1 - Le recueil

Règle 1: Le DP doit être codé selon la CIM-10.
"""

        # Appliquer les mappings (ne devrait rien changer)
        updated_text = manager._apply_code_mappings(text, "guide_mco", code_mapper)

        # Le texte devrait être inchangé
        assert updated_text == text

    def test_apply_code_mappings_preserves_unknown_codes(self, temp_data_dir):
        """Test que les codes inconnus sont préservés."""
        from pipeline_mco_pmsi.referentiels import CodeMapper

        manager = ReferentielsManager(data_dir=temp_data_dir)
        code_mapper = CodeMapper()  # Aucun mapping

        # Texte avec codes
        text = """A00.0 Code 1
A00.1 Code 2
A00.2 Code 3
"""

        # Appliquer les mappings (ne devrait rien changer)
        updated_text = manager._apply_code_mappings(text, "cim10", code_mapper)

        # Le texte devrait être inchangé
        assert updated_text == text

