"""Tests for timeout duration parsing.

Unit tests for core.timeout_parser.parse_timeout function.
"""

import pytest

from anima.core.timeout_parser import parse_timeout


class TestParseTimeout:
    """Tests for parse_timeout with various formats."""

    # -------------------------------------------------------------------------
    # Seconds
    # -------------------------------------------------------------------------

    def test_seconds_simple(self) -> None:
        """Parse simple seconds."""
        assert parse_timeout("30s") == 30
        assert parse_timeout("45s") == 45
        assert parse_timeout("1s") == 1

    def test_seconds_bare_number(self) -> None:
        """Parse bare number as seconds."""
        assert parse_timeout("30") == 30
        assert parse_timeout("1") == 1
        assert parse_timeout("100") == 100

    def test_seconds_case_insensitive(self) -> None:
        """Parse seconds case-insensitively."""
        assert parse_timeout("30S") == 30
        assert parse_timeout("30S") == 30

    def test_seconds_whitespace(self) -> None:
        """Parse seconds with whitespace."""
        assert parse_timeout(" 30s ") == 30
        assert parse_timeout("\t30s\t") == 30

    def test_seconds_word(self) -> None:
        """Parse 'seconds' word."""
        assert parse_timeout("30 seconds") == 30
        assert parse_timeout("30 second") == 30

    # -------------------------------------------------------------------------
    # Minutes
    # -------------------------------------------------------------------------

    def test_minutes_simple(self) -> None:
        """Parse simple minutes."""
        assert parse_timeout("10m") == 600
        assert parse_timeout("5m") == 300
        assert parse_timeout("1m") == 60

    def test_minutes_case_insensitive(self) -> None:
        """Parse minutes case-insensitively."""
        assert parse_timeout("10M") == 600
        assert parse_timeout("10M") == 600

    def test_minutes_whitespace(self) -> None:
        """Parse minutes with whitespace."""
        assert parse_timeout(" 10m ") == 600

    def test_minutes_word(self) -> None:
        """Parse 'minutes' word."""
        assert parse_timeout("10 minutes") == 600
        assert parse_timeout("10 minute") == 600

    def test_minutes_fractional(self) -> None:
        """Parse fractional minutes."""
        assert parse_timeout("1.5m") == 90
        assert parse_timeout("0.5m") == 30

    # -------------------------------------------------------------------------
    # Hours
    # -------------------------------------------------------------------------

    def test_hours_simple(self) -> None:
        """Parse simple hours."""
        assert parse_timeout("2h") == 7200
        assert parse_timeout("1h") == 3600
        assert parse_timeout("24h") == 86400

    def test_hours_case_insensitive(self) -> None:
        """Parse hours case-insensitively."""
        assert parse_timeout("2H") == 7200
        assert parse_timeout("2H") == 7200

    def test_hours_whitespace(self) -> None:
        """Parse hours with whitespace."""
        assert parse_timeout(" 2h ") == 7200

    def test_hours_word(self) -> None:
        """Parse 'hours' word."""
        assert parse_timeout("2 hours") == 7200
        assert parse_timeout("2 hour") == 7200

    def test_hours_fractional(self) -> None:
        """Parse fractional hours."""
        assert parse_timeout("1.5h") == 5400
        assert parse_timeout("0.5h") == 1800

    # -------------------------------------------------------------------------
    # Zero values
    # -------------------------------------------------------------------------

    def test_zero_seconds(self) -> None:
        """Parse zero seconds."""
        assert parse_timeout("0s") == 0
        assert parse_timeout("0") == 0

    def test_zero_minutes(self) -> None:
        """Parse zero minutes."""
        assert parse_timeout("0m") == 0

    def test_zero_hours(self) -> None:
        """Parse zero hours."""
        assert parse_timeout("0h") == 0

    # -------------------------------------------------------------------------
    # Large values
    # -------------------------------------------------------------------------

    def test_large_seconds(self) -> None:
        """Parse large second values."""
        assert parse_timeout("1000s") == 1000
        assert parse_timeout("86400s") == 86400

    def test_large_minutes(self) -> None:
        """Parse large minute values."""
        assert parse_timeout("90m") == 5400
        assert parse_timeout("1440m") == 86400

    # -------------------------------------------------------------------------
    # Error cases
    # -------------------------------------------------------------------------

    def test_invalid_format_no_number(self) -> None:
        """Reject format with no number."""
        # No number triggers contract error (PreContractError)
        with pytest.raises(Exception):  # PreContractError
            parse_timeout("abc")

    def test_invalid_unit(self) -> None:
        """Reject invalid unit."""
        with pytest.raises(ValueError):
            parse_timeout("10d")

    def test_empty_string(self) -> None:
        """Reject empty string (contract violation)."""
        with pytest.raises(Exception):  # PreContractError
            parse_timeout("")

    def test_whitespace_only(self) -> None:
        """Reject whitespace only (contract violation)."""
        with pytest.raises(Exception):  # PreContractError
            parse_timeout("   ")

    def test_negative_seconds(self) -> None:
        """Reject negative values (contract violation)."""
        with pytest.raises(Exception):  # PreContractError
            parse_timeout("-10s")

    # -------------------------------------------------------------------------
    # Edge cases
    # -------------------------------------------------------------------------

    def test_float_seconds(self) -> None:
        """Parse float seconds (truncates to int)."""
        assert parse_timeout("30.5s") == 30
        assert parse_timeout("0.5s") == 0

    def test_multiple_words(self) -> None:
        """Parse with multiple words."""
        assert parse_timeout("30 seconds") == 30
        assert parse_timeout("10 minutes") == 600
