"""Tests para theils_u."""

import os
import sys

sys.path.insert(0, os.path.dirname(__file__))

from theils_u import theils_u


def test_b_determines_a_gives_one():
    """Si b determina por completo a, U(a|b) debe ser ~1.0."""
    # Cada valor de b mapea a un unico valor de a (relacion funcional b -> a).
    a = ["x", "x", "y", "y", "z", "z"]
    b = ["1", "1", "2", "2", "3", "3"]
    u = theils_u(a, b)
    assert abs(u - 1.0) < 1e-9


def test_asymmetry_n_to_one_relation():
    """Relacion N:1: la ciudad determina el pais pero no al reves.

    theils_u(a, b) != theils_u(b, a) cuando la relacion es N:1.
    """
    ciudad = ["Madrid", "Barcelona", "Paris", "Lyon", "Roma", "Milan"]
    pais = ["ES", "ES", "FR", "FR", "IT", "IT"]
    # Conocer la ciudad elimina toda la incertidumbre del pais.
    u_pais_given_ciudad = theils_u(pais, ciudad)
    # Conocer el pais solo reduce parcialmente la incertidumbre de la ciudad.
    u_ciudad_given_pais = theils_u(ciudad, pais)

    assert abs(u_pais_given_ciudad - 1.0) < 1e-9
    assert u_ciudad_given_pais < 1.0
    # Asimetria explicita.
    assert u_pais_given_ciudad != u_ciudad_given_pais


def test_independence_gives_zero():
    """Si a y b son independientes, U(a|b) debe ser ~0.0."""
    # a alterna x/y; b alterna 1/2 de forma cruzada -> b no informa sobre a.
    a = ["x", "y", "x", "y", "x", "y", "x", "y"]
    b = ["1", "1", "2", "2", "1", "1", "2", "2"]
    u = theils_u(a, b)
    assert abs(u) < 1e-9


def test_fewer_than_two_pairs_returns_zero():
    """Con menos de 2 pares validos devuelve 0.0, no None ni excepcion."""
    assert theils_u([], []) == 0.0
    assert theils_u(["x"], ["1"]) == 0.0


def test_constant_a_returns_zero():
    """Si a es constante (H(a)==0) no hay incertidumbre que eliminar -> 0.0."""
    a = ["x", "x", "x", "x"]
    b = ["1", "2", "3", "4"]
    assert theils_u(a, b) == 0.0


def test_none_pairs_discarded():
    """Los pares con algun None se descartan antes de calcular."""
    a = ["x", "x", "y", "y", None, "z"]
    b = ["1", "1", "2", "2", "3", None]
    # Tras descartar los pares con None quedan 4 pares con b->a funcional.
    u = theils_u(a, b)
    assert abs(u - 1.0) < 1e-9


def test_result_in_unit_interval():
    """El resultado siempre cae en [0.0, 1.0]."""
    a = ["x", "y", "x", "z", "y", "z", "x", "y"]
    b = ["1", "2", "1", "3", "2", "3", "2", "1"]
    u = theils_u(a, b)
    assert 0.0 <= u <= 1.0
