"""
Tests for core functionality.
"""

import time

import pytest

from gattopy.core import (
    MemoryProfiler,
    Profiler,
    ProfileResult,
    TimeProfiler,
)


class TestProfileResult:
    """Test cases for ProfileResult class."""

    def test_initialization(self):
        """Test ProfileResult initialization."""
        result = ProfileResult(
            function_name="test_func",
            execution_time=1.5,
            memory_peak=10.5,
            memory_current=8.2,
        )

        assert result.function_name == "test_func"
        assert result.execution_time == 1.5
        assert result.memory_peak == 10.5
        assert result.memory_current == 8.2
        assert result.calls_count == 1

    def test_str_representation(self):
        """Test string representation."""
        result = ProfileResult(
            function_name="test_func", execution_time=0.001, memory_peak=5.5
        )

        str_repr = str(result)
        assert "test_func" in str_repr
        assert "1.00 ms" in str_repr or "ms" in str_repr
        assert "5.50 MB" in str_repr

    def test_to_dict(self):
        """Test conversion to dictionary."""
        result = ProfileResult(
            function_name="test_func", execution_time=1.0, memory_peak=10.0
        )

        result_dict = result.to_dict()
        assert result_dict["function_name"] == "test_func"
        assert result_dict["execution_time"] == 1.0
        assert result_dict["memory_peak_mb"] == 10.0

    def test_format_time(self):
        """Test time formatting."""
        # Test nanoseconds
        assert "ns" in ProfileResult._format_time(1e-9)

        # Test microseconds
        assert "μs" in ProfileResult._format_time(1e-5)

        # Test milliseconds
        assert "ms" in ProfileResult._format_time(0.001)

        # Test seconds
        assert "s" in ProfileResult._format_time(1.5)


class TestTimeProfiler:
    """Test cases for TimeProfiler class."""

    def test_context_manager(self):
        """Test TimeProfiler as context manager."""
        with TimeProfiler("test_operation") as profiler:
            time.sleep(0.01)  # Sleep for 10ms

        assert profiler.result is not None
        assert profiler.result.function_name == "test_operation"
        assert profiler.result.execution_time >= 0.01
        assert profiler.result.execution_time < 0.1  # Should be less than 100ms

    def test_elapsed_property(self):
        """Test elapsed property."""
        with TimeProfiler("test") as profiler:
            time.sleep(0.01)
            elapsed = profiler.elapsed
            assert elapsed >= 0.01

        # After context, elapsed should be final
        assert profiler.elapsed is not None


class TestMemoryProfiler:
    """Test cases for MemoryProfiler class."""

    def test_context_manager(self):
        """Test MemoryProfiler as context manager."""
        with MemoryProfiler("memory_test") as profiler:
            # Allocate some memory
            data = [i for i in range(100000)]

        assert profiler.result is not None
        assert profiler.result.function_name == "memory_test"
        assert profiler.result.memory_peak is not None
        assert profiler.result.memory_current is not None
        assert profiler.result.memory_peak > 0

    def test_memory_tracking(self):
        """Test that memory tracking works."""
        with MemoryProfiler("test") as profiler:
            # Allocate significant memory
            large_list = [i**2 for i in range(500000)]

        # Should track some memory
        assert profiler.result.memory_peak > 0
        assert profiler.result.memory_current >= 0


class TestProfiler:
    """Test cases for combined Profiler class."""

    def test_time_and_memory_tracking(self):
        """Test combined time and memory profiling."""
        with Profiler("combined_test") as profiler:
            time.sleep(0.01)
            data = [i for i in range(100000)]

        assert profiler.result is not None
        assert profiler.result.execution_time >= 0.01
        assert profiler.result.memory_peak > 0
        assert profiler.result.memory_current >= 0

    def test_time_only_tracking(self):
        """Test profiler with memory tracking disabled."""
        with Profiler("time_only", track_memory=False) as profiler:
            time.sleep(0.01)

        assert profiler.result is not None
        assert profiler.result.execution_time >= 0.01
        assert profiler.result.memory_peak is None
        assert profiler.result.memory_current is None

    def test_elapsed_property(self):
        """Test elapsed property during execution."""
        with Profiler("test") as profiler:
            time.sleep(0.01)
            elapsed = profiler.elapsed
            assert elapsed >= 0.01

        assert profiler.elapsed is not None
