from __future__ import annotations

from unittest.mock import MagicMock, patch

from yslow.checks.wifi import run, summary, _parse_bitrate
from yslow.diagnosis import _analyze_wifi
from yslow.models import WifiBand, WifiResult, Severity


# --- WifiBand ---


class TestWifiBand:
    def test_2_4_ghz(self):
        assert WifiBand.from_frequency(2412) == WifiBand.BAND_2_4
        assert WifiBand.from_frequency(2484) == WifiBand.BAND_2_4

    def test_5_ghz(self):
        assert WifiBand.from_frequency(5180) == WifiBand.BAND_5
        assert WifiBand.from_frequency(5825) == WifiBand.BAND_5

    def test_6_ghz(self):
        assert WifiBand.from_frequency(5955) == WifiBand.BAND_6
        assert WifiBand.from_frequency(7115) == WifiBand.BAND_6


# --- summary ---


class TestSummary:
    def test_none(self):
        assert "not available" in summary(None)

    def test_with_bitrate(self):
        result = WifiResult(
            interface="wlp1s0",
            signal_dbm=-52,
            signal_avg_dbm=-51,
            frequency_mhz=5180,
            band=WifiBand.BAND_5,
            tx_bitrate_mbps=866.7,
            rx_bitrate_mbps=400.0,
        )
        text = summary(result)
        assert "-52 dBm" in text
        assert "5 GHz" in text
        assert "867 Mbps TX" in text
        assert "400 Mbps RX" in text

    def test_without_bitrate(self):
        result = WifiResult(
            interface="wlp1s0",
            signal_dbm=-65,
            signal_avg_dbm=-64,
            frequency_mhz=2437,
            band=WifiBand.BAND_2_4,
            tx_bitrate_mbps=None,
            rx_bitrate_mbps=None,
        )
        text = summary(result)
        assert "-65 dBm" in text
        assert "2.4 GHz" in text
        assert "TX" not in text


# --- _parse_bitrate ---


class TestParseBitrate:
    def test_none_nla(self):
        assert _parse_bitrate(None) is None

    def test_bitrate32(self):
        nla = MagicMock()
        nla.get_attr.side_effect = lambda k: (
            8667 if k == "NL80211_RATE_INFO_BITRATE32" else None
        )
        assert _parse_bitrate(nla) == 866.7

    def test_bitrate16_fallback(self):
        nla = MagicMock()

        def _get(k):
            if k == "NL80211_RATE_INFO_BITRATE32":
                return None
            if k == "NL80211_RATE_INFO_BITRATE":
                return 540
            return None

        nla.get_attr.side_effect = _get
        assert _parse_bitrate(nla) == 54.0


# --- run ---


class TestRun:
    @patch("yslow.checks.wifi.platform")
    def test_non_linux_returns_none(self, mock_platform):
        mock_platform.system.return_value = "Darwin"
        assert run() is None

    @patch("yslow.checks.wifi.get_wireless_interface", return_value=None)
    @patch("yslow.checks.wifi.platform")
    def test_no_wifi_interface_returns_none(self, mock_platform, mock_iface):
        mock_platform.system.return_value = "Linux"
        assert run() is None

    @patch("yslow.checks.wifi.get_wireless_interface", return_value="wlp1s0")
    @patch("yslow.checks.wifi.platform")
    def test_import_error_returns_none(self, mock_platform, mock_iface):
        mock_platform.system.return_value = "Linux"
        with patch.dict("sys.modules", {"pyroute2": None}):
            # Force re-import to trigger ImportError
            assert run() is None


# --- _analyze_wifi ---


class TestAnalyzeWifi:
    def _result(self, signal: int) -> WifiResult:
        return WifiResult(
            interface="wlp1s0",
            signal_dbm=signal,
            signal_avg_dbm=signal,
            frequency_mhz=5180,
            band=WifiBand.BAND_5,
            tx_bitrate_mbps=866.7,
            rx_bitrate_mbps=400.0,
        )

    def test_good_signal_no_issues(self):
        issues, alerts = _analyze_wifi(self._result(-50))
        assert issues == []
        assert alerts == []

    def test_weak_signal_warning(self):
        issues, alerts = _analyze_wifi(self._result(-72))
        assert len(issues) == 1
        assert issues[0].severity == Severity.WARNING
        assert issues[0].kind == "wifi-signal"
        assert len(alerts) == 1
        assert alerts[0].severity == Severity.WARNING

    def test_very_weak_signal_error(self):
        issues, alerts = _analyze_wifi(self._result(-80))
        assert len(issues) == 1
        assert issues[0].severity == Severity.ERROR
        assert issues[0].kind == "wifi-signal"
