"""Tests for odds conversion and market math utilities."""

import pytest

from altsportsdata.odds import (
    decimal_to_american,
    american_to_decimal,
    to_probability,
    to_decimal,
    remove_vig,
    margin,
)


class TestDecimalToAmerican:
    def test_positive_odds(self):
        assert decimal_to_american(2.50) == 150

    def test_negative_odds(self):
        assert decimal_to_american(1.50) == -200

    def test_even_money(self):
        assert decimal_to_american(2.0) == 100

    def test_heavy_favorite(self):
        assert decimal_to_american(1.10) == -1000

    def test_big_underdog(self):
        assert decimal_to_american(11.0) == 1000

    def test_invalid_below_one(self):
        with pytest.raises(ValueError):
            decimal_to_american(0.5)

    def test_exactly_one(self):
        # Edge case: odds of 1.0 means no profit
        result = decimal_to_american(1.0)
        assert isinstance(result, int)


class TestAmericanToDecimal:
    def test_positive(self):
        assert american_to_decimal(150) == 2.5

    def test_negative(self):
        assert american_to_decimal(-200) == 1.5

    def test_even(self):
        assert american_to_decimal(100) == 2.0

    def test_heavy_favorite(self):
        assert american_to_decimal(-1000) == 1.1

    def test_big_underdog(self):
        assert american_to_decimal(1000) == 11.0

    def test_zero_raises(self):
        with pytest.raises(ValueError):
            american_to_decimal(0)


class TestRoundTrip:
    """Verify conversions are inverses of each other."""

    @pytest.mark.parametrize("decimal", [1.10, 1.50, 2.0, 2.50, 5.0, 11.0])
    def test_decimal_roundtrip(self, decimal):
        american = decimal_to_american(decimal)
        back = american_to_decimal(american)
        assert abs(back - decimal) < 0.02

    @pytest.mark.parametrize("american", [-1000, -200, -110, 100, 150, 500, 1000])
    def test_american_roundtrip(self, american):
        decimal = american_to_decimal(american)
        back = decimal_to_american(decimal)
        assert abs(back - american) <= 1


class TestToProbability:
    def test_even_money(self):
        assert to_probability(2.0) == 50.0

    def test_favorite(self):
        assert to_probability(1.50) == 66.67

    def test_underdog(self):
        assert to_probability(2.50) == 40.0

    def test_zero_raises(self):
        with pytest.raises(ValueError):
            to_probability(0)

    def test_negative_raises(self):
        with pytest.raises(ValueError):
            to_probability(-1.5)


class TestToDecimal:
    def test_fifty_percent(self):
        assert to_decimal(50.0) == 2.0

    def test_forty_percent(self):
        assert to_decimal(40.0) == 2.5

    def test_boundary_zero(self):
        with pytest.raises(ValueError):
            to_decimal(0)

    def test_boundary_hundred(self):
        with pytest.raises(ValueError):
            to_decimal(100)

    def test_over_hundred(self):
        with pytest.raises(ValueError):
            to_decimal(150)


class TestProbabilityRoundTrip:
    @pytest.mark.parametrize("prob", [10.0, 25.0, 33.33, 50.0, 75.0, 90.0])
    def test_roundtrip(self, prob):
        decimal = to_decimal(prob)
        back = to_probability(decimal)
        assert abs(back - prob) < 0.1


class TestRemoveVig:
    def test_basic(self):
        fair = remove_vig([52.4, 37.6, 25.0])
        assert abs(sum(fair) - 100.0) < 0.1

    def test_already_fair(self):
        fair = remove_vig([50.0, 30.0, 20.0])
        assert abs(sum(fair) - 100.0) < 0.1
        assert fair == [50.0, 30.0, 20.0]

    def test_two_outcomes(self):
        fair = remove_vig([55.0, 55.0])
        assert abs(sum(fair) - 100.0) < 0.1
        assert fair[0] == fair[1]  # symmetric

    def test_preserves_ratios(self):
        fair = remove_vig([60.0, 30.0, 25.0])
        # 60:30 ratio should be preserved
        assert abs(fair[0] / fair[1] - 2.0) < 0.01

    def test_empty(self):
        assert remove_vig([]) == []

    def test_all_zeros_raises(self):
        with pytest.raises(ValueError):
            remove_vig([0, 0, 0])


class TestMargin:
    def test_overround(self):
        assert margin([52.4, 37.6, 25.0]) == 15.0

    def test_fair_market(self):
        assert margin([50.0, 30.0, 20.0]) == 0.0

    def test_two_way(self):
        assert margin([55.0, 55.0]) == 10.0

    def test_empty(self):
        assert margin([]) == 0.0
