"""
Tests for decorators.
"""

import time

import pytest

from gattopy.decorators import profile, profile_memory, profile_time


class TestProfileTime:
    """Test cases for profile_time decorator."""

    def test_basic_decoration(self):
        """Test basic time profiling decoration."""

        @profile_time(print_result=False)
        def sample_function():
            time.sleep(0.01)
            return "test"

        result = sample_function()
        assert result == "test"
        assert sample_function.last_profile is not None
        assert sample_function.last_profile.execution_time >= 0.01

    def test_without_parentheses(self):
        """Test decorator without parentheses."""

        @profile_time
        def sample_function():
            return "test"

        result = sample_function()
        assert result == "test"
        assert hasattr(sample_function, "last_profile")

    def test_function_name_preserved(self):
        """Test that function name is preserved."""

        @profile_time(print_result=False)
        def my_function():
            return 42

        assert my_function.__name__ == "my_function"
        my_function()
        assert my_function.last_profile.function_name == "my_function"

    def test_with_arguments(self):
        """Test decorator on function with arguments."""

        @profile_time(print_result=False)
        def add_numbers(a, b):
            return a + b

        result = add_numbers(5, 3)
        assert result == 8
        assert add_numbers.last_profile is not None


class TestProfileMemory:
    """Test cases for profile_memory decorator."""

    def test_basic_decoration(self):
        """Test basic memory profiling decoration."""

        @profile_memory(print_result=False)
        def create_list():
            return [i for i in range(100000)]

        result = create_list()
        assert len(result) == 100000
        assert create_list.last_profile is not None
        assert create_list.last_profile.memory_peak > 0

    def test_without_parentheses(self):
        """Test decorator without parentheses."""

        @profile_memory
        def sample_function():
            return [1, 2, 3]

        result = sample_function()
        assert result == [1, 2, 3]
        assert hasattr(sample_function, "last_profile")

    def test_memory_tracking(self):
        """Test that memory is actually tracked."""

        @profile_memory(print_result=False)
        def allocate_memory():
            return [i**2 for i in range(500000)]

        allocate_memory()
        assert allocate_memory.last_profile.memory_peak > 0
        assert allocate_memory.last_profile.memory_current >= 0


class TestProfile:
    """Test cases for combined profile decorator."""

    def test_combined_profiling(self):
        """Test combined time and memory profiling."""

        @profile(print_result=False)
        def combined_function():
            time.sleep(0.01)
            return [i for i in range(100000)]

        result = combined_function()
        assert len(result) == 100000
        assert combined_function.last_profile is not None
        assert combined_function.last_profile.execution_time >= 0.01
        assert combined_function.last_profile.memory_peak > 0

    def test_time_only_mode(self):
        """Test profiling with memory tracking disabled."""

        @profile(print_result=False, track_memory=False)
        def time_only_function():
            time.sleep(0.01)
            return "done"

        result = time_only_function()
        assert result == "done"
        assert time_only_function.last_profile.execution_time >= 0.01
        assert time_only_function.last_profile.memory_peak is None

    def test_without_parentheses(self):
        """Test decorator without parentheses."""

        @profile
        def sample_function():
            return "test"

        result = sample_function()
        assert result == "test"
        assert hasattr(sample_function, "last_profile")

    def test_return_value_preserved(self):
        """Test that return values are preserved."""

        @profile(print_result=False)
        def get_data():
            return {"key": "value", "number": 42}

        result = get_data()
        assert result == {"key": "value", "number": 42}

    def test_exception_handling(self):
        """Test that exceptions are properly propagated."""

        @profile(print_result=False)
        def failing_function():
            raise ValueError("Test error")

        with pytest.raises(ValueError, match="Test error"):
            failing_function()
