"""Tests for Pydantic response models."""

from mcjtag.models import (
    ConnectionStatus,
    FlashBankInfo,
    FlashBanksResult,
    FlashProgramResult,
    JTAGChain,
    JTAGShiftResult,
    MemoryDump,
    MemorySearchResult,
    MemoryWriteResult,
    RawCommandResult,
    RegisterSet,
    RegisterWriteResult,
    SVDFieldResult,
    SVDListResult,
    SVDPeripheralResult,
    SVDRegisterResult,
    TAPResult,
    TargetControlResult,
    TargetStateResult,
    TransportInfo,
)


class TestConnectionStatus:
    def test_connected(self):
        status = ConnectionStatus(connected=True, host="localhost", port=6666, message="ok")
        assert status.connected is True
        assert status.port == 6666

    def test_disconnected(self):
        status = ConnectionStatus(connected=False, message="Disconnected")
        assert status.connected is False
        assert status.host is None

    def test_with_pid(self):
        status = ConnectionStatus(connected=True, process_pid=12345)
        assert status.process_pid == 12345


class TestTargetStateResult:
    def test_halted(self):
        result = TargetStateResult(
            state="halted", pc="0x08001234", halted=True, name="stm32f1x.cpu"
        )
        assert result.halted is True
        assert result.pc == "0x08001234"

    def test_running(self):
        result = TargetStateResult(state="running", halted=False)
        assert result.halted is False
        assert result.pc is None


class TestTargetControlResult:
    def test_halt(self):
        result = TargetControlResult(action="halt", state="halted", pc="0x08001234", halted=True)
        assert result.action == "halt"
        assert result.halted is True

    def test_reset_run(self):
        result = TargetControlResult(action="reset_run", state="running", halted=False)
        assert result.state == "running"


class TestMemoryDump:
    def test_basic(self):
        dump = MemoryDump(
            address="0x08000000",
            width=32,
            count=4,
            values=["0x20005000", "0x08001001", "0x08001003", "0x08001005"],
            hexdump=(
                "08000000: 00 50 00 20 01 10 00 08  03 10 00 08 05 10 00 08  |.P. ............|"
            ),
        )
        assert dump.count == 4
        assert len(dump.values) == 4
        assert dump.width == 32

    def test_byte_read(self):
        dump = MemoryDump(
            address="0x20000000",
            width=8,
            count=2,
            values=["0x48", "0x65"],
            hexdump="20000000: 48 65                                             |He|",
        )
        assert dump.width == 8


class TestMemoryWriteResult:
    def test_write(self):
        result = MemoryWriteResult(address="0x20000000", width=32, count=1, written=True)
        assert result.written is True


class TestMemorySearchResult:
    def test_found(self):
        result = MemorySearchResult(
            pattern="DEADBEEF",
            start="0x08000000",
            end="0x08020000",
            matches=["0x08001234", "0x08005678"],
            count=2,
        )
        assert result.count == 2

    def test_not_found(self):
        result = MemorySearchResult(
            pattern="BAADF00D",
            start="0x08000000",
            end="0x08020000",
            matches=[],
            count=0,
        )
        assert result.count == 0


class TestRegisterSet:
    def test_registers(self, sample_register_values):
        hex_regs = {k: f"0x{v:08x}" for k, v in sample_register_values.items()}
        result = RegisterSet(registers=hex_regs, count=len(hex_regs))
        assert result.count == 7
        assert result.registers["pc"] == "0x08001234"


class TestRegisterWriteResult:
    def test_write(self):
        result = RegisterWriteResult(name="pc", value="0x08001000", written=True)
        assert result.name == "pc"
        assert result.written is True


class TestFlashBankInfo:
    def test_bank(self):
        bank = FlashBankInfo(
            index=0,
            name="stm32f1x.flash",
            base="0x08000000",
            size=131072,
            sectors=128,
            target="stm32f1x",
        )
        assert bank.size == 131072
        assert bank.sectors == 128


class TestFlashBanksResult:
    def test_banks(self):
        result = FlashBanksResult(
            banks=[
                FlashBankInfo(
                    index=0,
                    name="stm32f1x.flash",
                    base="0x08000000",
                    size=131072,
                    sectors=128,
                    target="stm32f1x",
                )
            ],
            count=1,
        )
        assert result.count == 1


class TestFlashProgramResult:
    def test_success(self):
        result = FlashProgramResult(
            path="/tmp/firmware.bin",
            erased=True,
            verified=True,
            success=True,
            message="Programmed firmware.bin successfully",
        )
        assert result.success is True

    def test_failure(self):
        result = FlashProgramResult(
            path="/tmp/firmware.bin",
            erased=True,
            verified=False,
            success=False,
            message="Verification failed",
        )
        assert result.success is False


class TestTAPResult:
    def test_tap(self, sample_idcode):
        tap = TAPResult(
            name="stm32f1x.cpu",
            idcode=f"0x{sample_idcode:08x}",
            ir_length=4,
            enabled=True,
        )
        assert tap.enabled is True
        assert tap.idcode == "0x3ba00477"


class TestJTAGChain:
    def test_chain(self, sample_idcode):
        chain = JTAGChain(
            taps=[
                TAPResult(
                    name="stm32f1x.cpu",
                    idcode=f"0x{sample_idcode:08x}",
                    ir_length=4,
                    enabled=True,
                )
            ],
            count=1,
        )
        assert chain.count == 1


class TestJTAGShiftResult:
    def test_irscan(self):
        result = JTAGShiftResult(
            operation="irscan",
            tap="stm32f1x.cpu",
            value_in="0x0E",
            value_out="0x01",
        )
        assert result.operation == "irscan"

    def test_drscan(self):
        result = JTAGShiftResult(
            operation="drscan",
            tap="stm32f1x.cpu",
            value_in="0x00000000",
            value_out="0x3ba00477",
            bits=32,
        )
        assert result.bits == 32


class TestSVDModels:
    def test_field(self):
        field = SVDFieldResult(
            name="ODR0",
            value=1,
            width=1,
            offset=0,
            description="Port output data bit 0",
        )
        assert field.value == 1

    def test_register(self):
        reg = SVDRegisterResult(
            name="ODR",
            address="0x4001080C",
            raw_value="0x00000001",
            fields=[
                SVDFieldResult(
                    name="ODR0",
                    value=1,
                    width=1,
                    offset=0,
                    description="Port output data bit 0",
                )
            ],
        )
        assert len(reg.fields) == 1

    def test_peripheral(self):
        result = SVDPeripheralResult(
            peripheral="GPIOA",
            registers={
                "ODR": SVDRegisterResult(
                    name="ODR",
                    address="0x4001080C",
                    raw_value="0x00000001",
                    fields=[],
                )
            },
        )
        assert result.peripheral == "GPIOA"
        assert "ODR" in result.registers

    def test_list_result(self):
        result = SVDListResult(
            peripherals=["GPIOA", "GPIOB", "USART1"],
            svd_loaded=True,
        )
        assert result.svd_loaded is True
        assert len(result.peripherals) == 3


class TestRawCommandResult:
    def test_raw(self):
        result = RawCommandResult(
            command="version",
            response="Open On-Chip Debugger 0.12.0",
        )
        assert "0.12.0" in result.response


class TestTransportInfo:
    def test_transport(self):
        info = TransportInfo(
            transport="swd",
            adapter="cmsis-dap",
            speed_khz=4000,
            available_transports=["jtag", "swd"],
        )
        assert info.transport == "swd"
        assert info.speed_khz == 4000
