import pytest

from python_reference import grade_band, score_percentage, score_summary


@pytest.mark.parametrize(
    ("earned", "possible", "expected"),
    [(0, 20, 0.0), (18, 20, 90.0), (2, 3, 66.67)],
)
def test_score_percentage(earned: float, possible: float, expected: float) -> None:
    assert score_percentage(earned, possible) == expected


@pytest.mark.parametrize(
    ("earned", "possible"),
    [(-1, 20), (21, 20), (0, 0)],
)
def test_score_percentage_rejects_invalid_values(
    earned: float, possible: float
) -> None:
    with pytest.raises(ValueError):
        score_percentage(earned, possible)


@pytest.mark.parametrize(
    ("percentage", "expected"),
    [(100, "A"), (90, "A"), (89.99, "B"), (60, "D"), (59.99, "F"), (0, "F")],
)
def test_grade_band_boundaries(percentage: float, expected: str) -> None:
    assert grade_band(percentage) == expected


@pytest.mark.parametrize("percentage", [-0.01, 100.01])
def test_grade_band_rejects_out_of_range(percentage: float) -> None:
    with pytest.raises(ValueError):
        grade_band(percentage)


def test_score_summary_for_multiple_values() -> None:
    assert score_summary([72, 90, 84, 90]) == (72, 90, 84.0)


def test_score_summary_for_one_value() -> None:
    assert score_summary([65]) == (65, 65, 65.0)


@pytest.mark.parametrize("scores", [[], [-1, 50], [50, 101]])
def test_score_summary_rejects_invalid_input(scores: list[int]) -> None:
    with pytest.raises(ValueError):
        score_summary(scores)
