from lr_modbus.client import ModbusClient, ModbusDeviceError
from lr_modbus.codec import build_frame


class FakeTransport:
    def __init__(self, responses):
        self.responses = list(responses)
        self.requests = []

    def transact(self, payload: bytes, *, deadline=None) -> bytes:
        self.requests.append(payload)
        if not self.responses:
            raise AssertionError("No response queued")
        return self.responses.pop(0)


def test_read_holding_registers_round_trip() -> None:
    response_payload = bytes([4, 0x00, 0x2A, 0x00, 0x2B])
    transport = FakeTransport([build_frame(1, 3, response_payload)])
    client = ModbusClient(transport, unit_id=1)

    values = client.read_holding_registers(0, 2)

    assert values == [0x2A, 0x2B]
    assert transport.requests[0] == build_frame(1, 3, b"\x00\x00\x00\x02")


def test_write_single_register_exception() -> None:
    exception_payload = bytes([2])
    transport = FakeTransport([build_frame(1, 0x86, exception_payload)])
    client = ModbusClient(transport, unit_id=1)

    try:
        client.write_single_register(1, 10)
    except ModbusDeviceError as exc:
        assert exc.exception_code == 2
    else:  # pragma: no cover - safety net
        raise AssertionError("Expected ModbusDeviceError")
