"""Tests for Poisson confidence interval using Garwood method."""

import numpy as np
import pytest
from scipy.stats import chi2

from gri_utils.stats import poisson_ci


def test_single_count() -> None:
    """Test CI for a single count value."""
    lower, upper = poisson_ci(10)
    assert isinstance(lower, float)
    assert isinstance(upper, float)
    assert lower < 10 < upper


def test_single_count_known_values() -> None:
    """Test against known Garwood CI values."""
    # For count=10 with 95% CI, expected bounds are approximately 4.80 and 18.39
    lower, upper = poisson_ci(10, confidence=0.95)
    assert lower == pytest.approx(4.7954, rel=1e-3)
    assert upper == pytest.approx(18.3904, rel=1e-3)


def test_zero_count() -> None:
    """Test CI for zero count - lower bound should be 0."""
    lower, upper = poisson_ci(0)
    assert lower == 0.0
    assert upper > 0


def test_array_input() -> None:
    """Test CI for array of counts."""
    counts = np.array([5, 10, 15, 20])
    lower, upper = poisson_ci(counts)
    assert isinstance(lower, np.ndarray)
    assert isinstance(upper, np.ndarray)
    assert lower.shape == counts.shape
    assert upper.shape == counts.shape
    assert np.all(lower < counts)
    assert np.all(upper > counts)


def test_list_input() -> None:
    """Test CI for list of counts."""
    counts = [5, 10, 15]
    lower, _upper = poisson_ci(counts)
    assert isinstance(lower, np.ndarray)
    assert len(lower) == 3


def test_confidence_levels() -> None:
    """Test different confidence levels - wider CI for higher confidence."""
    lower_95, upper_95 = poisson_ci(10, confidence=0.95)
    lower_99, upper_99 = poisson_ci(10, confidence=0.99)

    # 99% CI should be wider than 95% CI
    assert lower_99 < lower_95
    assert upper_99 > upper_95


def test_garwood_formula() -> None:
    """Verify the implementation matches the Garwood formula directly."""
    k = 15
    alpha = 0.05  # 95% confidence

    expected_lower = chi2.ppf(alpha / 2, 2 * k) / 2
    expected_upper = chi2.ppf(1 - alpha / 2, 2 * (k + 1)) / 2

    lower, upper = poisson_ci(k, confidence=0.95)
    assert lower == pytest.approx(expected_lower)
    assert upper == pytest.approx(expected_upper)


@pytest.mark.parametrize(
    ("count", "conf"),
    [
        (1, 0.95),
        (5, 0.90),
        (100, 0.99),
        (0, 0.95),
    ],
)
def test_ci_contains_count(count: int, conf: float) -> None:
    """Test that CI contains the observed count (except for edge cases)."""
    lower, upper = poisson_ci(count, confidence=conf)
    # The observed count should typically be within the CI
    # (though this is not guaranteed for very small counts)
    if count > 0:
        assert lower < count < upper
