"""
Tests pour le Document Processor.

Ce module teste la segmentation de documents cliniques et la gestion multi-documents.
"""

import pytest
from datetime import datetime

from src.pipeline_mco_pmsi.processors.document_processor import (
    DocumentProcessor,
    DOCUMENT_TYPE_PRIORITIES,
)
from src.pipeline_mco_pmsi.models.clinical import (
    ClinicalDocument,
    Section,
    StructuredStay,
)
from src.pipeline_mco_pmsi.models.metadata import StayMetadata


@pytest.fixture
def document_processor():
    """Fixture pour créer un DocumentProcessor."""
    return DocumentProcessor()


@pytest.fixture
def stay_metadata():
    """Fixture pour créer des métadonnées de séjour."""
    return StayMetadata(
        stay_id="stay_001",
        admission_date=datetime(2024, 1, 1, 10, 0),
        discharge_date=datetime(2024, 1, 5, 14, 0),
        specialty="Chirurgie",
        unit="Bloc A",
        age=45,
        sex="M",
    )


@pytest.fixture
def simple_document():
    """Fixture pour créer un document simple."""
    return ClinicalDocument(
        document_id="doc_001",
        document_type="cr_medical",
        content="Patient admis pour douleurs abdominales.",
        creation_date=datetime(2024, 1, 1, 12, 0),
        author="Dr. Martin",
        priority=2,
    )


@pytest.fixture
def structured_document():
    """Fixture pour créer un document avec sections structurées."""
    content = """Anamnèse
Patient de 45 ans, admis pour douleurs abdominales aiguës.

Examen clinique
Abdomen tendu, défense généralisée.

Diagnostic
Appendicite aiguë.

Traitement
Appendicectomie sous cœlioscopie."""
    
    return ClinicalDocument(
        document_id="doc_002",
        document_type="cr_operatoire",
        content=content,
        creation_date=datetime(2024, 1, 2, 9, 0),
        author="Dr. Dupont",
        priority=1,
    )


class TestDocumentProcessor:
    """Tests pour la classe DocumentProcessor."""

    def test_init(self, document_processor):
        """Test l'initialisation du DocumentProcessor."""
        assert document_processor is not None
        assert hasattr(document_processor, "_compiled_patterns")
        assert len(document_processor._compiled_patterns) > 0

    def test_process_documents_empty_list(
        self, document_processor, stay_metadata
    ):
        """Test que process_documents lève une erreur avec une liste vide."""
        with pytest.raises(ValueError, match="ne peut pas être vide"):
            document_processor.process_documents([], stay_metadata)

    def test_process_documents_single_document(
        self, document_processor, simple_document, stay_metadata
    ):
        """Test le traitement d'un seul document."""
        result = document_processor.process_documents(
            [simple_document], stay_metadata
        )

        assert isinstance(result, StructuredStay)
        assert result.stay_id == stay_metadata.stay_id
        assert len(result.documents) == 1
        assert result.documents[0].document_id == simple_document.document_id
        assert len(result.sections) > 0

    def test_process_documents_assigns_priorities(
        self, document_processor, stay_metadata
    ):
        """Test que les priorités sont correctement assignées."""
        # Créer des documents de différents types
        docs = [
            ClinicalDocument(
                document_id="doc_courrier",
                document_type="courrier",
                content="Courrier de sortie.",
                creation_date=datetime(2024, 1, 1, 10, 0),
                author="Dr. A",
                priority=5,  # Sera réassigné
            ),
            ClinicalDocument(
                document_id="doc_cro",
                document_type="cr_operatoire",
                content="Compte rendu opératoire.",
                creation_date=datetime(2024, 1, 2, 10, 0),
                author="Dr. B",
                priority=5,  # Sera réassigné
            ),
            ClinicalDocument(
                document_id="doc_crm",
                document_type="cr_medical",
                content="Compte rendu médical.",
                creation_date=datetime(2024, 1, 3, 10, 0),
                author="Dr. C",
                priority=5,  # Sera réassigné
            ),
        ]

        result = document_processor.process_documents(docs, stay_metadata)

        # Vérifier que les documents sont triés par priorité
        assert len(result.documents) == 3
        assert result.documents[0].document_type == "cr_operatoire"  # priorité 1
        assert result.documents[0].priority == 1
        assert result.documents[1].document_type == "cr_medical"  # priorité 2
        assert result.documents[1].priority == 2
        assert result.documents[2].document_type == "courrier"  # priorité 5
        assert result.documents[2].priority == 5

    def test_process_documents_multi_documents(
        self, document_processor, stay_metadata
    ):
        """Test le traitement de plusieurs documents."""
        docs = [
            ClinicalDocument(
                document_id="doc_1",
                document_type="biologie",
                content="Résultats de biologie.",
                creation_date=datetime(2024, 1, 1, 10, 0),
                author="Lab",
                priority=4,
            ),
            ClinicalDocument(
                document_id="doc_2",
                document_type="cr_operatoire",
                content="Intervention chirurgicale.",
                creation_date=datetime(2024, 1, 2, 10, 0),
                author="Dr. Chirurgien",
                priority=1,
            ),
            ClinicalDocument(
                document_id="doc_3",
                document_type="imagerie",
                content="Scanner abdominal.",
                creation_date=datetime(2024, 1, 1, 15, 0),
                author="Dr. Radiologue",
                priority=3,
            ),
        ]

        result = document_processor.process_documents(docs, stay_metadata)

        # Vérifier l'ordre des priorités (CRO > imagerie > biologie)
        assert len(result.documents) == 3
        assert result.documents[0].document_type == "cr_operatoire"
        assert result.documents[1].document_type == "imagerie"
        assert result.documents[2].document_type == "biologie"

        # Vérifier que toutes les sections sont présentes
        assert len(result.sections) >= 3  # Au moins une section par document

    def test_segment_document_no_sections(
        self, document_processor, simple_document
    ):
        """Test la segmentation d'un document sans sections détectables."""
        sections = document_processor.segment_document(simple_document)

        # Doit créer une section "autre" avec tout le contenu
        assert len(sections) == 1
        assert sections[0].section_type == "autre"
        assert sections[0].content == simple_document.content
        assert sections[0].span.start == 0
        assert sections[0].span.end == len(simple_document.content)

    def test_segment_document_with_sections(
        self, document_processor, structured_document
    ):
        """Test la segmentation d'un document avec sections structurées."""
        sections = document_processor.segment_document(structured_document)

        # Doit détecter plusieurs sections
        assert len(sections) >= 4

        # Vérifier les types de sections détectés
        section_types = [s.section_type for s in sections]
        assert "anamnese" in section_types
        assert "examen" in section_types
        assert "diagnostic" in section_types
        assert "traitement" in section_types

        # Vérifier que chaque section a un contenu non vide
        for section in sections:
            assert len(section.content) > 0
            assert section.span.end > section.span.start

    def test_segment_document_section_order(
        self, document_processor, structured_document
    ):
        """Test que les sections sont dans l'ordre du document."""
        sections = document_processor.segment_document(structured_document)

        # Vérifier que les positions sont croissantes
        for i in range(len(sections) - 1):
            assert sections[i].span.start <= sections[i + 1].span.start

    def test_detect_section_type_anamnese(self, document_processor):
        """Test la détection de sections anamnèse."""
        assert document_processor._detect_section_type("Anamnèse") == "anamnese"
        assert document_processor._detect_section_type("Histoire de la maladie") == "anamnese"
        assert document_processor._detect_section_type("ANTÉCÉDENTS") == "anamnese"

    def test_detect_section_type_examen(self, document_processor):
        """Test la détection de sections examen."""
        assert document_processor._detect_section_type("Examen clinique") == "examen"
        assert document_processor._detect_section_type("Examen physique") == "examen"
        assert document_processor._detect_section_type("Inspection") == "examen"

    def test_detect_section_type_diagnostic(self, document_processor):
        """Test la détection de sections diagnostic."""
        assert document_processor._detect_section_type("Diagnostic") == "diagnostic"
        assert document_processor._detect_section_type("Conclusion diagnostique") == "diagnostic"
        assert document_processor._detect_section_type("Diagnostic retenu") == "diagnostic"

    def test_detect_section_type_traitement(self, document_processor):
        """Test la détection de sections traitement."""
        assert document_processor._detect_section_type("Traitement") == "traitement"
        assert document_processor._detect_section_type("Traitement prescrit") == "traitement"
        assert document_processor._detect_section_type("Prescription") == "traitement"

    def test_detect_section_type_evolution(self, document_processor):
        """Test la détection de sections évolution."""
        assert document_processor._detect_section_type("Évolution") == "evolution"
        assert document_processor._detect_section_type("Suites") == "evolution"
        assert document_processor._detect_section_type("Évolution post-opératoire") == "evolution"

    def test_detect_section_type_conclusion(self, document_processor):
        """Test la détection de sections conclusion."""
        assert document_processor._detect_section_type("Conclusion") == "conclusion"
        assert document_processor._detect_section_type("Synthèse") == "conclusion"

    def test_detect_section_type_no_match(self, document_processor):
        """Test qu'aucune section n'est détectée pour du texte normal."""
        assert document_processor._detect_section_type("Patient admis") is None
        assert document_processor._detect_section_type("") is None
        assert document_processor._detect_section_type("   ") is None

    def test_detect_section_type_case_insensitive(self, document_processor):
        """Test que la détection est insensible à la casse."""
        assert document_processor._detect_section_type("ANAMNÈSE") == "anamnese"
        assert document_processor._detect_section_type("anamnèse") == "anamnese"
        assert document_processor._detect_section_type("Anamnèse") == "anamnese"

    def test_create_section(self, document_processor):
        """Test la création d'une section."""
        lines = ["Anamnèse", "Patient de 45 ans", "Douleurs abdominales"]
        section = document_processor._create_section(
            document_id="doc_001",
            section_type="anamnese",
            lines=lines,
            start_pos=0,
            section_idx=0,
        )

        assert section.section_id == "doc_001_section_0"
        assert section.section_type == "anamnese"
        assert "Anamnèse" in section.content
        assert "Patient de 45 ans" in section.content
        assert section.span.start == 0
        assert section.span.end > 0

    def test_document_type_priorities_complete(self):
        """Test que toutes les priorités de types de documents sont définies."""
        expected_types = [
            "cr_operatoire",
            "cr_medical",
            "imagerie",
            "biologie",
            "courrier",
            "autre",
        ]
        
        for doc_type in expected_types:
            assert doc_type in DOCUMENT_TYPE_PRIORITIES
            assert 1 <= DOCUMENT_TYPE_PRIORITIES[doc_type] <= 5

    def test_document_type_priorities_order(self):
        """Test que les priorités respectent l'ordre attendu."""
        # CRO doit avoir la priorité la plus haute (1)
        assert DOCUMENT_TYPE_PRIORITIES["cr_operatoire"] == 1
        
        # CRM doit avoir la deuxième priorité
        assert DOCUMENT_TYPE_PRIORITIES["cr_medical"] == 2
        
        # Imagerie doit avoir la troisième priorité
        assert DOCUMENT_TYPE_PRIORITIES["imagerie"] == 3
        
        # Biologie doit avoir la quatrième priorité
        assert DOCUMENT_TYPE_PRIORITIES["biologie"] == 4
        
        # Courriers et autres doivent avoir la priorité la plus basse
        assert DOCUMENT_TYPE_PRIORITIES["courrier"] == 5
        assert DOCUMENT_TYPE_PRIORITIES["autre"] == 5

    def test_segment_document_complex_structure(self, document_processor):
        """Test la segmentation d'un document avec structure complexe."""
        content = """COMPTE RENDU OPÉRATOIRE

Anamnèse
Patient de 65 ans, diabétique, hypertendu.
Admis pour douleurs abdominales aiguës depuis 24h.

Examen clinique
Abdomen tendu, défense généralisée.
Température 38.5°C.

Diagnostic
Appendicite aiguë compliquée.
Suspicion de péritonite.

Traitement
Appendicectomie en urgence sous cœlioscopie.
Antibiothérapie large spectre.

Évolution
Suites opératoires simples.
Sortie à J+3.

Conclusion
Intervention réussie sans complication."""

        doc = ClinicalDocument(
            document_id="doc_complex",
            document_type="cr_operatoire",
            content=content,
            creation_date=datetime(2024, 1, 1, 10, 0),
            author="Dr. Chirurgien",
            priority=1,
        )

        sections = document_processor.segment_document(doc)

        # Doit détecter toutes les sections
        assert len(sections) >= 6
        
        section_types = [s.section_type for s in sections]
        assert "anamnese" in section_types
        assert "examen" in section_types
        assert "diagnostic" in section_types
        assert "traitement" in section_types
        assert "evolution" in section_types
        assert "conclusion" in section_types

    def test_segment_document_preserves_content(self, document_processor):
        """Test que la segmentation préserve tout le contenu."""
        content = """Anamnèse
Patient admis.

Diagnostic
Appendicite."""

        doc = ClinicalDocument(
            document_id="doc_test",
            document_type="cr_medical",
            content=content,
            creation_date=datetime(2024, 1, 1, 10, 0),
            author="Dr. Test",
            priority=2,
        )

        sections = document_processor.segment_document(doc)

        # Reconstituer le contenu à partir des sections
        reconstructed = "\n".join(s.content for s in sections)
        
        # Le contenu doit être préservé (modulo les sauts de ligne)
        assert "Patient admis" in reconstructed
        assert "Appendicite" in reconstructed

    def test_process_documents_validates_stay_id(
        self, document_processor, simple_document, stay_metadata
    ):
        """Test que le stay_id est correctement propagé."""
        result = document_processor.process_documents(
            [simple_document], stay_metadata
        )

        assert result.stay_id == stay_metadata.stay_id

    def test_segment_document_empty_content(self, document_processor):
        """Test la segmentation d'un document avec contenu minimal."""
        doc = ClinicalDocument(
            document_id="doc_empty",
            document_type="cr_medical",
            content="X",  # Contenu minimal (min_length=1)
            creation_date=datetime(2024, 1, 1, 10, 0),
            author="Dr. Test",
            priority=2,
        )

        sections = document_processor.segment_document(doc)

        # Doit créer au moins une section
        assert len(sections) >= 1
        assert sections[0].content == "X"


class TestDocumentProcessorIntegration:
    """Tests d'intégration pour le DocumentProcessor."""

    def test_full_workflow_single_document(
        self, document_processor, structured_document, stay_metadata
    ):
        """Test le workflow complet avec un seul document."""
        result = document_processor.process_documents(
            [structured_document], stay_metadata
        )

        # Vérifier la structure complète
        assert isinstance(result, StructuredStay)
        assert result.stay_id == stay_metadata.stay_id
        assert len(result.documents) == 1
        assert len(result.sections) >= 4
        assert result.facts == []  # Pas encore de faits extraits

        # Vérifier que les sections sont valides
        for section in result.sections:
            assert section.section_id.startswith(structured_document.document_id)
            assert section.section_type in [
                "anamnese",
                "examen",
                "diagnostic",
                "traitement",
                "evolution",
                "conclusion",
                "autre",
            ]
            assert len(section.content) > 0

    def test_full_workflow_multi_documents(
        self, document_processor, stay_metadata
    ):
        """Test le workflow complet avec plusieurs documents."""
        # Créer un séjour complet avec plusieurs documents
        docs = [
            ClinicalDocument(
                document_id="doc_admission",
                document_type="cr_medical",
                content="""Anamnèse
Patient admis pour douleurs abdominales.

Examen clinique
Abdomen sensible.""",
                creation_date=datetime(2024, 1, 1, 10, 0),
                author="Dr. Urgentiste",
                priority=2,
            ),
            ClinicalDocument(
                document_id="doc_operation",
                document_type="cr_operatoire",
                content="""Diagnostic
Appendicite aiguë.

Traitement
Appendicectomie sous cœlioscopie.""",
                creation_date=datetime(2024, 1, 2, 9, 0),
                author="Dr. Chirurgien",
                priority=1,
            ),
            ClinicalDocument(
                document_id="doc_imagerie",
                document_type="imagerie",
                content="Scanner abdominal : appendice inflammatoire.",
                creation_date=datetime(2024, 1, 1, 15, 0),
                author="Dr. Radiologue",
                priority=3,
            ),
        ]

        result = document_processor.process_documents(docs, stay_metadata)

        # Vérifier la structure
        assert len(result.documents) == 3
        
        # Vérifier l'ordre des priorités
        assert result.documents[0].document_type == "cr_operatoire"
        assert result.documents[1].document_type == "cr_medical"
        assert result.documents[2].document_type == "imagerie"

        # Vérifier que toutes les sections sont présentes
        assert len(result.sections) >= 3

        # Vérifier que les sections proviennent de différents documents
        doc_ids = set(s.section_id.split("_section_")[0] for s in result.sections)
        assert len(doc_ids) == 3
