from __future__ import annotations

import json
from pathlib import Path

from app.case_epicrisis.application.utils import normalize_cie10_entries
from app.services.clinical_document_service import ClinicalDocumentService
from modules.processing.cie10.RANGES_HTML import CIE10CatalogResolver, CIE10Retriever


ROOT = Path(__file__).resolve().parents[1]


def _retriever() -> CIE10Retriever:
    retriever = CIE10Retriever.__new__(CIE10Retriever)
    retriever.catalogo = CIE10CatalogResolver(
        json.loads((ROOT / "cie10_estructura_completa.json").read_text(encoding="utf-8"))
    )
    return retriever


def test_explicit_code_precedes_semantic_resolution_and_accepts_point_variants() -> None:
    retriever = _retriever()

    result = normalize_cie10_entries(
        [{"diagnostico": "Lesión condral documentada", "codigo": "M24.1"}],
        retriever=retriever,
        source="historia_clinica",
    )[0]

    assert result["codigo"] == "M241"
    assert result["estado_codificacion"] == "codificado"
    assert result["origen"] == "documento_explicito"
    assert result["es_hoja"] is True


def test_group_code_is_valid_but_remains_provisional() -> None:
    retriever = _retriever()

    result = normalize_cie10_entries(
        [{"diagnostico": "Trastorno articular", "codigo": "M24"}],
        retriever=retriever,
        source="quirurgico",
    )[0]

    assert result["codigo"] == "M24"
    assert result["estado_codificacion"] == "provisional_grupo"
    assert result["es_hoja"] is False
    assert result["razon_revision"]


def test_controlled_aliases_resolve_m241_m242_and_m751_without_llm() -> None:
    retriever = _retriever()

    results = normalize_cie10_entries(
        [
            {"diagnostico": "Condroplastia con lesión condral"},
            {"diagnostico": "Reparación de lesión ligamentaria"},
            {"diagnostico": "Tendinitis del supraespinoso"},
        ],
        retriever=retriever,
        source="quirurgico",
    )

    assert [item["codigo"] for item in results] == ["M241", "M242", "M751"]
    assert all(item["estado_codificacion"] == "codificado" for item in results)


def test_faiss_reranking_keeps_only_catalog_codes_and_prefers_leaf() -> None:
    retriever = _retriever()

    candidates = retriever.rerankear_candidatos(
        "lesión del ligamento del hombro",
        [
            {"codigo": "M24", "descripcion": "grupo", "score": 1.0},
            {"codigo": "M242", "descripcion": "trastorno del ligamento", "score": 0.6},
            {"codigo": "ZZZ", "descripcion": "irrelevante", "score": 2.0},
        ],
    )

    assert candidates[0]["codigo"] == "M242"
    assert candidates[0]["es_hoja"] is True
    assert all(item["codigo"] != "ZZZ" for item in candidates)


def test_surgical_inference_requires_clinical_evidence_and_keeps_traceability() -> None:
    service = ClinicalDocumentService.__new__(ClinicalDocumentService)
    service.cie10_retriever = _retriever()

    inferred = service._infer_quirurgico_cie10(
        {
            "tipo_documento": "quirurgico",
            "pagina": 3,
            "analysis_structured": {
                "pp": "Condroplastia de clavícula distal",
                "hl": "Lesión condral documentada.",
            },
        },
        procedimientos=["Condroplastia de clavícula distal"],
        existing=[],
    )

    assert [item["codigo"] for item in inferred] == ["M241"]
    assert inferred[0]["estado_codificacion"] == "inferido_revisable"
    assert inferred[0]["origen"] == "inferido_desde_procedimiento"
    assert inferred[0]["procedimiento_origen"] == "condroplastia"
    assert inferred[0]["pagina"] == 3
    assert inferred[0]["evidencia_clinica"]


def test_procedure_name_alone_does_not_become_a_diagnosis_and_trauma_is_warned() -> None:
    service = ClinicalDocumentService.__new__(ClinicalDocumentService)
    service.cie10_retriever = _retriever()

    assert service._infer_quirurgico_cie10({}, procedimientos=["Artroscopia de hombro"], existing=[]) == []

    inferred = service._infer_quirurgico_cie10(
        {
            "tipo_documento": "quirurgico",
            "analysis_structured": {
                "pp": "Reparación del supraespinoso",
                "hl": "Desgarro traumático del supraespinoso.",
            },
        },
        procedimientos=["Reparación del supraespinoso"],
        existing=[],
    )

    assert inferred[0]["codigo"] == "M751"
    assert inferred[0]["advertencias"]


def test_pop_is_not_resolved_as_cie10() -> None:
    retriever = _retriever()

    result = normalize_cie10_entries([{"diagnostico": "POP"}], retriever=retriever, source="quirurgico")

    assert result[0]["codigo"] == ""
    assert result[0]["estado_codificacion"] == "pendiente_validacion"
