"""Tests for math_utils module."""

import pytest

from perry_py_lib_template.math_utils import add, add_many, AddResult


class TestAdd:
    """Tests for the add function."""

    def test_add_integers(self) -> None:
        """Test adding two integers."""
        assert add(1, 2) == 3
        assert add(0, 0) == 0
        assert add(-1, 1) == 0
        assert add(-5, -3) == -8

    def test_add_floats(self) -> None:
        """Test adding two floats."""
        assert add(1.5, 2.5) == 4.0
        assert add(0.1, 0.2) == pytest.approx(0.3)

    def test_add_mixed(self) -> None:
        """Test adding int and float."""
        assert add(1, 2.5) == 3.5
        assert add(2.5, 1) == 3.5


class TestAddMany:
    """Tests for the add_many function."""

    def test_add_many_numbers(self) -> None:
        """Test adding multiple numbers."""
        result = add_many(1, 2, 3, 4, 5)
        assert isinstance(result, AddResult)
        assert result.value == 15
        assert result.operands == [1, 2, 3, 4, 5]

    def test_add_many_single(self) -> None:
        """Test adding a single number."""
        result = add_many(42)
        assert result.value == 42
        assert result.operands == [42]

    def test_add_many_floats(self) -> None:
        """Test adding multiple floats."""
        result = add_many(1.5, 2.5, 3.0)
        assert result.value == 7.0

    def test_add_many_empty(self) -> None:
        """Test that empty arguments raise ValueError."""
        with pytest.raises(ValueError, match="At least one number is required"):
            add_many()


class TestAddResult:
    """Tests for AddResult named tuple."""

    def test_add_result_creation(self) -> None:
        """Test creating AddResult directly."""
        result = AddResult(value=10, operands=[1, 2, 3, 4])
        assert result.value == 10
        assert result.operands == [1, 2, 3, 4]

    def test_add_result_immutable(self) -> None:
        """Test that AddResult is immutable."""
        result = AddResult(value=10, operands=[1, 2])
        with pytest.raises(AttributeError):
            result.value = 20  # type: ignore
