"""Tests for TelemetryService.

Contract: CNT-TUI-SVC-001
Traceability: UX-001
"""

import time
from unittest.mock import MagicMock, patch

import pytest

from laida_cli.tui.services.telemetry_service import TelemetryData, TelemetryService


class TestTelemetryData:
    """Tests for TelemetryData dataclass."""

    def test_create_telemetry_data(self) -> None:
        """TelemetryData can be created with all fields."""
        data = TelemetryData(
            session_elapsed_seconds=120.5,
            task_elapsed_seconds=45.0,
            last_result="✔ P0-S1",
            memory_mb=128,
            cpu_percent=25.5,
        )

        assert data.session_elapsed_seconds == 120.5
        assert data.task_elapsed_seconds == 45.0
        assert data.last_result == "✔ P0-S1"
        assert data.memory_mb == 128
        assert data.cpu_percent == 25.5

    def test_telemetry_data_is_frozen(self) -> None:
        """TelemetryData is immutable."""
        data = TelemetryData(
            session_elapsed_seconds=100.0,
            task_elapsed_seconds=None,
            last_result="--",
            memory_mb=64,
            cpu_percent=10.0,
        )

        with pytest.raises(AttributeError):
            data.memory_mb = 256  # type: ignore[misc]


class TestTelemetryService:
    """Tests for TelemetryService."""

    def test_initial_state(self) -> None:
        """Service starts with default values."""
        service = TelemetryService()
        data = service.get_data()

        assert data.last_result == "--"
        assert data.task_elapsed_seconds is None
        assert data.session_elapsed_seconds >= 0

    def test_session_time_increases(self) -> None:
        """Session time increases over time."""
        service = TelemetryService()

        data1 = service.get_data()
        time.sleep(0.1)  # Small delay
        data2 = service.get_data()

        assert data2.session_elapsed_seconds > data1.session_elapsed_seconds

    def test_start_task_enables_task_time(self) -> None:
        """Starting a task enables task time tracking."""
        service = TelemetryService()

        # Before starting, task time is None
        assert service.get_data().task_elapsed_seconds is None

        # After starting, task time is tracked
        service.start_task()
        data = service.get_data()

        assert data.task_elapsed_seconds is not None
        assert data.task_elapsed_seconds >= 0

    def test_end_task_records_success(self) -> None:
        """Ending a successful task updates last_result."""
        service = TelemetryService()
        service.start_task()

        service.end_task(success=True, phase=0, step=1)
        data = service.get_data()

        assert data.last_result == "✔ P0-S1"
        assert data.task_elapsed_seconds is None  # Timer cleared

    def test_end_task_records_failure(self) -> None:
        """Ending a failed task updates last_result with failure marker."""
        service = TelemetryService()
        service.start_task()

        service.end_task(success=False, phase=2, step=3)
        data = service.get_data()

        assert data.last_result == "✘ P2-S3"
        assert data.task_elapsed_seconds is None

    def test_reset_task_clears_timer(self) -> None:
        """Reset task clears timer without recording result."""
        service = TelemetryService()
        service.start_task()
        service.reset_task()

        data = service.get_data()
        assert data.task_elapsed_seconds is None
        assert data.last_result == "--"  # Unchanged

    @patch("laida_cli.tui.services.telemetry_service.psutil.Process")
    def test_get_data_includes_memory(self, mock_process_class: MagicMock) -> None:
        """get_data includes memory usage from psutil."""
        mock_process = MagicMock()
        mock_process.memory_info.return_value.rss = 50 * 1024 * 1024  # 50 MB
        mock_process.cpu_percent.return_value = 15.5
        mock_process_class.return_value = mock_process

        service = TelemetryService()
        data = service.get_data()

        assert data.memory_mb == 50
        assert data.cpu_percent == 15.5


class TestFormatDuration:
    """Tests for duration formatting functions."""

    def test_format_zero(self) -> None:
        """Zero seconds formats as 00:00:00."""
        assert TelemetryService.format_duration(0) == "00:00:00"

    def test_format_seconds_only(self) -> None:
        """Under a minute shows only seconds."""
        assert TelemetryService.format_duration(45) == "00:00:45"

    def test_format_minutes_and_seconds(self) -> None:
        """Minutes and seconds format correctly."""
        assert TelemetryService.format_duration(125) == "00:02:05"

    def test_format_hours(self) -> None:
        """Hours format correctly."""
        assert TelemetryService.format_duration(3723) == "01:02:03"

    def test_format_task_time_none(self) -> None:
        """None task time shows placeholder."""
        assert TelemetryService.format_task_time(None) == "--:--"

    def test_format_task_time_seconds(self) -> None:
        """Task time formats as MM:SS."""
        assert TelemetryService.format_task_time(125.5) == "02:05"

    def test_format_task_time_zero(self) -> None:
        """Zero task time formats as 00:00."""
        assert TelemetryService.format_task_time(0) == "00:00"
