"""Tests for utils.resource — Hardware detection and resource monitoring."""

import os
from unittest.mock import patch, mock_open

import pytest

from utils.resource import (
    get_hardware_tier,
    get_memory_info,
    get_cpu_temperature,
    get_disk_usage,
    get_process_resources,
    detect_hardware,
    HardwareInfo,
    TIER_GENERIC,
    TIER_PI_ZERO,
    TIER_OPI_ZERO3,
)


class TestResource:

    def test_detect_hardware_tier(self):
        """get_hardware_tier() returns a valid tier string."""
        tier = get_hardware_tier()
        assert tier in (TIER_GENERIC, TIER_PI_ZERO, TIER_OPI_ZERO3)

    def test_detect_hardware_info(self):
        """detect_hardware() returns a HardwareInfo dataclass."""
        info = detect_hardware()
        assert isinstance(info, HardwareInfo)
        assert info.tier in (TIER_GENERIC, TIER_PI_ZERO, TIER_OPI_ZERO3)
        assert info.cpu_cores >= 1
        assert isinstance(info.architecture, str)
        assert len(info.architecture) > 0

    def test_get_memory_info(self):
        """get_memory_info() returns a dict with MemTotal and MemAvailable."""
        info = get_memory_info()
        assert isinstance(info, dict)
        # On Linux, /proc/meminfo should be available
        if os.path.exists("/proc/meminfo"):
            assert "MemTotal" in info
            assert info["MemTotal"] > 0

    def test_get_cpu_temperature(self):
        """get_cpu_temperature() returns a float or None (no crash)."""
        temp = get_cpu_temperature()
        # May be None if no thermal zone is available (CI/container)
        if temp is not None:
            assert isinstance(temp, float)
            # Sanity check: between -20 and 120 Celsius
            assert -20 <= temp <= 120

    def test_get_disk_usage(self):
        """get_disk_usage() returns (total_gb, free_gb, used_pct) for /."""
        total_gb, free_gb, used_pct = get_disk_usage("/")

        assert isinstance(total_gb, float)
        assert isinstance(free_gb, float)
        assert isinstance(used_pct, float)

        assert total_gb > 0
        assert free_gb >= 0
        assert 0 <= used_pct <= 100

    def test_get_process_resources(self):
        """get_process_resources() returns stats for the current PID."""
        pid = os.getpid()
        result = get_process_resources(pid)

        # Should succeed for our own PID on Linux
        if result is not None:
            assert result.pid == pid
            assert result.rss_mb >= 0
            assert result.vms_mb >= 0
            assert result.threads >= 1
            assert isinstance(result.name, str)
            assert isinstance(result.state, str)

    def test_get_process_resources_invalid_pid(self):
        """get_process_resources() returns None for a non-existent PID."""
        result = get_process_resources(999999999)
        assert result is None
