"""Tests unitaires du module pipeline.referentials.

Compatible pytest ET exécution directe (`python tests/test_referentials.py`).
Nécessite que la base SQLite ait déjà été construite :
    python -m pipeline.referentials --build
"""
from __future__ import annotations

import sys
from pathlib import Path

# Permet l'exécution directe depuis tests/ sans installer le package.
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from pipeline.referentials import (  # noqa: E402
    DB_PATH,
    ghm_to_ghs,
    get_cim10_libelle,
    is_valid_ccam,
    is_valid_cim10,
    is_valid_ghm,
    is_valid_ghs,
    nearest_cim10,
)


# ---------------------------------------------------------------------------
# CIM-10
# ---------------------------------------------------------------------------

def test_cim10_codes_valides():
    """Quelques codes courants du référentiel PMSI."""
    assert is_valid_cim10("K650")     # Péritonite aigüe
    assert is_valid_cim10("T814")     # Infection après acte
    assert is_valid_cim10("I10")      # Hypertension essentielle
    assert is_valid_cim10("Z515")     # Soins palliatifs
    assert is_valid_cim10("C509")     # Tumeur maligne du sein


def test_cim10_normalisation():
    """Tolère le point décimal (K65.0) et la casse (k650)."""
    assert is_valid_cim10("K65.0")
    assert is_valid_cim10("k650")
    assert is_valid_cim10(" K650 ")


def test_cim10_codes_invalides():
    assert not is_valid_cim10("")
    assert not is_valid_cim10("ZZZ99")
    assert not is_valid_cim10("K6501234")   # trop long
    assert not is_valid_cim10("1234")       # ne commence pas par lettre
    assert not is_valid_cim10("K65X")       # suffixe non numérique


def test_cim10_libelle():
    lib = get_cim10_libelle("K650")
    assert lib is not None and "éritonit" in lib.lower() or "peritonit" in lib.lower()


def test_cim10_nearest_correction_ocr():
    # O (lettre) lu au lieu de 0 (chiffre)
    assert nearest_cim10("K65O") == "K650"
    # Code déjà valide : renvoyé tel quel
    assert nearest_cim10("K650") == "K650"
    # Aucune correspondance à distance <= 1
    assert nearest_cim10("ZZZZZ", max_distance=1) is None


# ---------------------------------------------------------------------------
# CCAM
# ---------------------------------------------------------------------------

def test_ccam_codes_valides():
    assert is_valid_ccam("EBFA012")
    assert is_valid_ccam("HFCC003")   # Bypass gastrique (mentionné dans la V5)
    assert is_valid_ccam("ebfa012")   # casse insensible
    assert is_valid_ccam("EBFA012-1") # extension PMSI tolérée


def test_ccam_codes_invalides():
    assert not is_valid_ccam("AAAA000")
    assert not is_valid_ccam("")
    assert not is_valid_ccam("EBF012")   # 3 lettres au lieu de 4


# ---------------------------------------------------------------------------
# GHM
# ---------------------------------------------------------------------------

def test_ghm_codes_valides():
    assert is_valid_ghm("01C031")
    assert is_valid_ghm("01c031")


def test_ghm_codes_invalides():
    assert not is_valid_ghm("99Z99Z")
    assert not is_valid_ghm("")
    assert not is_valid_ghm("ABCDEF")


# ---------------------------------------------------------------------------
# GHS et couplage GHM→GHS
# ---------------------------------------------------------------------------

def test_ghs_valide():
    assert is_valid_ghs("22")
    assert is_valid_ghs("0022")   # zéros de tête tolérés
    assert not is_valid_ghs("99999")
    assert not is_valid_ghs("")


def test_ghm_to_ghs():
    ghs = ghm_to_ghs("01C031")
    assert "22" in ghs
    # GHM inexistant → liste vide
    assert ghm_to_ghs("99Z99Z") == []


# ---------------------------------------------------------------------------
# Exécution directe (sans pytest)
# ---------------------------------------------------------------------------

def _main() -> int:
    import traceback
    tests = [
        ("test_cim10_codes_valides",         test_cim10_codes_valides),
        ("test_cim10_normalisation",         test_cim10_normalisation),
        ("test_cim10_codes_invalides",       test_cim10_codes_invalides),
        ("test_cim10_libelle",               test_cim10_libelle),
        ("test_cim10_nearest_correction_ocr", test_cim10_nearest_correction_ocr),
        ("test_ccam_codes_valides",          test_ccam_codes_valides),
        ("test_ccam_codes_invalides",        test_ccam_codes_invalides),
        ("test_ghm_codes_valides",           test_ghm_codes_valides),
        ("test_ghm_codes_invalides",         test_ghm_codes_invalides),
        ("test_ghs_valide",                  test_ghs_valide),
        ("test_ghm_to_ghs",                  test_ghm_to_ghs),
    ]
    if not DB_PATH.exists():
        print(f"ERREUR : base SQLite manquante ({DB_PATH}).")
        print("Exécute d'abord : python -m pipeline.referentials --build")
        return 2

    failures = 0
    for name, fn in tests:
        try:
            fn()
            print(f"  [OK ] {name}")
        except AssertionError as e:
            print(f"  [FAIL] {name} — {e}")
            failures += 1
        except Exception:
            print(f"  [ERR] {name}")
            traceback.print_exc()
            failures += 1
    print(f"=== {len(tests) - failures}/{len(tests)} tests OK ===")
    return 0 if failures == 0 else 1


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