from unittest.mock import MagicMock, patch

import pytest

from planemapper.provisioning import ProvisioningError, wifi


def test_provisioning_error_is_exception() -> None:
    assert issubclass(ProvisioningError, Exception)


def test_provisioning_error_can_be_raised_and_caught() -> None:
    try:
        raise ProvisioningError("test error")
    except ProvisioningError as e:
        assert str(e) == "test error"


def test_start_ap_raises_on_hostapd_failure() -> None:
    mock_fail = MagicMock()
    mock_fail.returncode = 1
    with patch("planemapper.provisioning.wifi._write_hostapd_conf"):
        with patch("planemapper.provisioning.wifi.subprocess.run", return_value=mock_fail):
            with pytest.raises(ProvisioningError, match="hostapd failed"):
                wifi.start_ap()


def test_start_ap_raises_on_dnsmasq_failure() -> None:
    mock_ok = MagicMock()
    mock_ok.returncode = 0
    mock_fail = MagicMock()
    mock_fail.returncode = 1
    with patch("planemapper.provisioning.wifi._write_hostapd_conf"):
        with patch(
            "planemapper.provisioning.wifi.subprocess.run",
            side_effect=[mock_ok, mock_fail],  # hostapd OK, dnsmasq fails
        ):
            with pytest.raises(ProvisioningError, match="dnsmasq failed"):
                wifi.start_ap()


def test_kill_wifi_raises_on_rfkill_failure() -> None:
    mock_fail = MagicMock()
    mock_fail.returncode = 1
    with patch("planemapper.provisioning.wifi.subprocess.run", return_value=mock_fail):
        with pytest.raises(ProvisioningError, match="rfkill failed"):
            wifi.kill_wifi()


def test_stop_ap_does_not_raise() -> None:
    mock_ok = MagicMock()
    mock_ok.returncode = 0
    with patch("planemapper.provisioning.wifi.subprocess.run", return_value=mock_ok):
        wifi.stop_ap()  # should not raise
