from __future__ import annotations

import struct

import pytest

from asm3042_flasher.firmware import FirmwareImage, MAX_FIRMWARE_SIZE


def test_rejects_empty_firmware() -> None:
    with pytest.raises(ValueError, match="empty"):
        FirmwareImage.from_bytes(b"")


def test_rejects_odd_sized_firmware() -> None:
    with pytest.raises(ValueError, match="even"):
        FirmwareImage.from_bytes(b"\x00")


def test_rejects_oversized_firmware() -> None:
    with pytest.raises(ValueError, match="too large"):
        FirmwareImage.from_bytes(b"\x00" * (MAX_FIRMWARE_SIZE + 2))


def test_detects_header_tags() -> None:
    image = FirmwareImage.from_bytes(
        b"\x00\x00\x01\x002214A_RCFG\x002214A_FW\x00\x00\x00", source="sample.bin"
    )

    assert image.family_tag == "2214A"
    assert image.header_tags == ("2214A_RCFG", "2214A_FW")


def test_iter_sram_writes_small_image() -> None:
    image = FirmwareImage.from_bytes(
        b"".join(struct.pack("<H", word) for word in (0x1000, 0x1001, 0x1002))
    )

    assert list(image.iter_sram_writes()) == [
        (0x0000, 0x00001000),
        (0x0002, 0x00001001),
        (0x0004, 0x00001002),
    ]


def test_iter_sram_writes_interleaves_second_bank() -> None:
    words = [0] * 0x4002
    words[0] = 0x00AA
    words[1] = 0x00BB
    words[2] = 0x00CC
    words[0x4000] = 0x1100
    words[0x4001] = 0x2200

    image = FirmwareImage.from_bytes(
        b"".join(struct.pack("<H", word) for word in words), source="interleave.bin"
    )

    writes = list(image.iter_sram_writes())

    assert writes[:3] == [
        (0x0000, 0x110000AA),
        (0x0002, 0x220000BB),
        (0x0004, 0x000000CC),
    ]
    assert len(writes) == 0x4000
