"""Tests para missingness_correlation."""

from datascience.missingness_correlation import missingness_correlation


def test_co_ocurrencia_fuerte_corr_uno_jaccard_uno():
    # a y b faltan EXACTAMENTE en las mismas filas -> corr 1.0, jaccard 1.0.
    mask = {
        "a": [1, 0, 1, 0, 1, 0],
        "b": [1, 0, 1, 0, 1, 0],
    }
    out = missingness_correlation(mask)
    assert out["columns"] == ["a", "b"]
    assert out["n_excluded"] == 0
    # Diagonal 1.0, off-diagonal ~1.0.
    assert out["matrix"][0][0] == 1.0
    assert out["matrix"][1][1] == 1.0
    assert abs(out["matrix"][0][1] - 1.0) < 1e-9
    assert len(out["pairs"]) == 1
    pair = out["pairs"][0]
    assert {pair["a"], pair["b"]} == {"a", "b"}
    assert abs(pair["corr"] - 1.0) < 1e-9
    assert pair["co_missing"] == 3       # filas 0,2,4
    assert pair["either_missing"] == 3   # mismas filas
    assert abs(pair["jaccard"] - 1.0) < 1e-9


def test_ausencias_disjuntas_corr_negativa_jaccard_cero():
    # a y b nunca faltan en la misma fila -> co_missing 0, jaccard 0, corr <= 0.
    mask = {
        "a": [1, 1, 0, 0],
        "b": [0, 0, 1, 1],
    }
    out = missingness_correlation(mask)
    assert out["columns"] == ["a", "b"]
    pair = out["pairs"][0]
    assert pair["co_missing"] == 0
    assert pair["either_missing"] == 4
    assert pair["jaccard"] == 0.0
    # Solapamiento nulo + ausencias complementarias -> correlacion negativa.
    assert pair["corr"] < 0.0
    assert abs(pair["corr"] - out["matrix"][0][1]) < 1e-12


def test_columna_sin_varianza_se_excluye():
    # c esta siempre presente (todo 0): no aporta ausencia -> no entra ni como
    # excluida. d esta siempre ausente (todo 1): tiene nulos pero sin varianza
    # -> excluida y n_excluded incrementa. a y b tienen varianza.
    mask = {
        "a": [1, 0, 1, 0],
        "b": [1, 0, 0, 0],
        "c": [0, 0, 0, 0],   # siempre presente
        "d": [1, 1, 1, 1],   # siempre ausente, constante
    }
    out = missingness_correlation(mask)
    assert out["columns"] == ["a", "b"]
    assert "d" in out["excluded_cols"]
    assert "c" not in out["excluded_cols"]
    assert out["n_excluded"] == 1
    # Matriz solo de las columnas con varianza.
    assert len(out["matrix"]) == 2
    assert len(out["matrix"][0]) == 2


def test_menos_de_dos_columnas_con_varianza_vacio_pero_cuenta_excluidas():
    # Solo una columna con varianza (a) + una constante-ausente (d).
    mask = {
        "a": [1, 0, 1, 0],
        "d": [1, 1, 1, 1],
    }
    out = missingness_correlation(mask)
    assert out["columns"] == []
    assert out["matrix"] == []
    assert out["pairs"] == []
    assert out["n_excluded"] == 1
    assert out["excluded_cols"] == ["d"]


def test_mask_vacio_todo_vacio():
    out = missingness_correlation({})
    assert out == {
        "columns": [],
        "matrix": [],
        "pairs": [],
        "n_excluded": 0,
        "excluded_cols": [],
    }


def test_top_k_limita_pares():
    # 4 columnas con varianza -> 6 pares; top_k=2 deja 2.
    mask = {
        "a": [1, 0, 1, 0, 0],
        "b": [1, 0, 0, 1, 0],
        "c": [0, 1, 1, 0, 1],
        "d": [1, 1, 0, 0, 1],
    }
    out = missingness_correlation(mask, top_k=2)
    assert len(out["columns"]) == 4
    assert len(out["pairs"]) == 2
    # Ordenados por |corr| desc.
    assert abs(out["pairs"][0]["corr"]) >= abs(out["pairs"][1]["corr"])


def test_no_lanza_con_entradas_raras():
    # Valores no-lista y no-dict no deben romper.
    assert missingness_correlation(None)["columns"] == []
    mask = {
        "a": [1, 0, 1, 0],
        "b": [1, 0, 1, 0],
        "bad": "not a list",
        "empty": [],
    }
    out = missingness_correlation(mask)
    assert out["columns"] == ["a", "b"]
