import pytest

from repeater.config import get_radio_for_board


class _DummyRadio:
    _initialized = True

    def begin(self):
        return True


def test_get_radio_for_board_passes_en_pins(monkeypatch):
    captured_kwargs = {}

    class _DummySX1262Radio:
        @classmethod
        def get_instance(cls, **kwargs):
            captured_kwargs.update(kwargs)
            return _DummyRadio()

    monkeypatch.setattr(
        "pymc_core.hardware.sx1262_wrapper.SX1262Radio",
        _DummySX1262Radio,
    )

    board_config = {
        "radio_type": "sx1262",
        "sx1262": {
            "bus_id": 0,
            "cs_id": 0,
            "cs_pin": -1,
            "reset_pin": 18,
            "busy_pin": 5,
            "irq_pin": 6,
            "txen_pin": -1,
            "rxen_pin": -1,
            "en_pins": [26, 23],
        },
        "radio": {
            "frequency": 915000000,
            "tx_power": 22,
            "spreading_factor": 9,
            "bandwidth": 125000,
            "coding_rate": 5,
            "preamble_length": 17,
            "sync_word": 0x3444,
        },
    }

    get_radio_for_board(board_config)

    assert captured_kwargs["en_pins"] == [26, 23]
    assert "en_pin" not in captured_kwargs


def test_get_radio_for_board_null_radio_type_returns_null_radio():
    radio = get_radio_for_board({"radio_type": None})
    assert type(radio).__name__ == "NullRadio"


def test_get_radio_for_board_missing_radio_type_returns_null_radio():
    radio = get_radio_for_board({})
    assert type(radio).__name__ == "NullRadio"


# ─── pymc_tcp / pymc_usb branches ────────────────────────────────────


def _pymc_radio_cfg():
    """Common radio params for the pymc_* tests."""
    return {
        "frequency": 869618000,
        "tx_power": 22,
        "spreading_factor": 8,
        "bandwidth": 62500,
        "coding_rate": 8,
        "preamble_length": 16,
        "sync_word": 0x12,
    }


def test_get_radio_for_board_pymc_tcp(monkeypatch):
    pytest.importorskip("pymc_core.hardware.tcp_radio")
    captured = {}

    class _DummyTCPLoRaRadio(_DummyRadio):
        def __init__(self, **kwargs):
            captured.update(kwargs)

    monkeypatch.setattr(
        "pymc_core.hardware.tcp_radio.TCPLoRaRadio",
        _DummyTCPLoRaRadio,
    )

    board_config = {
        "radio_type": "pymc_tcp",
        "pymc_tcp": {
            "host": "pymc-3e2834.local",
            "port": 5055,
            "token": "shared-secret",
            "connect_timeout": 7.5,
            "lbt_enabled": False,
            "lbt_max_attempts": 3,
        },
        "radio": _pymc_radio_cfg(),
    }

    get_radio_for_board(board_config)

    assert captured["host"] == "pymc-3e2834.local"
    assert captured["port"] == 5055
    assert captured["token"] == "shared-secret"
    assert captured["connect_timeout"] == 7.5
    assert captured["frequency"] == 869618000
    assert captured["sync_word"] == 0x12
    assert captured["lbt_enabled"] is False
    assert captured["lbt_max_attempts"] == 3


def test_get_radio_for_board_pymc_tcp_requires_host(monkeypatch):
    pytest.importorskip("pymc_core.hardware.tcp_radio")

    monkeypatch.setattr(
        "pymc_core.hardware.tcp_radio.TCPLoRaRadio",
        lambda **kwargs: _DummyRadio(),
    )

    board_config = {
        "radio_type": "pymc_tcp",
        "pymc_tcp": {"port": 5055},
        "radio": _pymc_radio_cfg(),
    }

    with pytest.raises(ValueError, match="Missing 'host'"):
        get_radio_for_board(board_config)


def test_get_radio_for_board_pymc_usb(monkeypatch):
    pytest.importorskip("pymc_core.hardware.usb_radio")
    captured = {}

    class _DummyUSBLoRaRadio(_DummyRadio):
        def __init__(self, **kwargs):
            captured.update(kwargs)

    monkeypatch.setattr(
        "pymc_core.hardware.usb_radio.USBLoRaRadio",
        _DummyUSBLoRaRadio,
    )

    board_config = {
        "radio_type": "pymc_usb",
        "pymc_usb": {
            "port": "/dev/ttyACM0",
            "baudrate": 921600,
        },
        "radio": _pymc_radio_cfg(),
    }

    get_radio_for_board(board_config)

    assert captured["port"] == "/dev/ttyACM0"
    assert captured["baudrate"] == 921600
    assert captured["frequency"] == 869618000
    assert captured["sync_word"] == 0x12
    # LBT defaults preserved when omitted from pymc_usb section.
    assert captured["lbt_enabled"] is True
    assert captured["lbt_max_attempts"] == 5


def test_get_radio_for_board_pymc_usb_requires_port(monkeypatch):
    pytest.importorskip("pymc_core.hardware.usb_radio")

    monkeypatch.setattr(
        "pymc_core.hardware.usb_radio.USBLoRaRadio",
        lambda **kwargs: _DummyRadio(),
    )

    board_config = {
        "radio_type": "pymc_usb",
        # Section present (baudrate set) but `port` deliberately omitted to
        # exercise the inner "Missing 'port'" guard rather than the outer
        # "Missing 'pymc_usb' section" one.
        "pymc_usb": {"baudrate": 921600},
        "radio": _pymc_radio_cfg(),
    }

    with pytest.raises(ValueError, match="Missing 'port'"):
        get_radio_for_board(board_config)
