"""Regression tests: parsers must not raise IndexError on short mfr_data (#494)."""

from __future__ import annotations

import pytest

from switchbot.adv_parsers.contact import process_wocontact
from switchbot.adv_parsers.leak import process_leak
from switchbot.adv_parsers.presence_sensor import process_presence_sensor


@pytest.mark.parametrize(
    "mfr_data",
    [b"", b"\x00", b"\x00\x01", b"\x00" * 8],
)
def test_process_leak_short_mfr_returns_empty(mfr_data: bytes) -> None:
    """Leak parser must not crash when mfr_data is shorter than 9 bytes."""
    data = b"&\x00N"
    assert process_leak(data, mfr_data) == {}


@pytest.mark.parametrize(
    "mfr_data",
    [b"", b"\x00" * 6, b"\x00" * 11],
)
def test_process_presence_sensor_short_mfr_returns_empty(mfr_data: bytes) -> None:
    """Presence sensor parser must not crash when mfr_data is shorter than 12 bytes."""
    assert process_presence_sensor(None, mfr_data) == {}


def test_process_presence_sensor_none_mfr_returns_empty() -> None:
    assert process_presence_sensor(None, None) == {}


@pytest.mark.parametrize(
    ("data", "mfr_data"),
    [
        (None, b""),
        (None, b"\x00" * 12),
        (b"", None),
        (b"\x00" * 8, None),
        (b"\x00", b"\x00" * 12),
        (b"\x00" * 8, b"\x00" * 12),
    ],
)
def test_process_wocontact_short_payloads_return_empty(
    data: bytes | None, mfr_data: bytes | None
) -> None:
    """Contact parser must not crash when neither payload is long enough."""
    assert process_wocontact(data, mfr_data) == {}


def test_process_wocontact_uses_mfr_when_data_short() -> None:
    """Long mfr_data lets the parser succeed even with short service data."""
    # mfr_data byte 7 = 0xF0 -> motion+light+contact_open+contact_timeout all True
    mfr_data = b"\x00\x00\x00\x00\x00\x00\x00\xf0\x00\x00\x00\x00\x02"
    result = process_wocontact(None, mfr_data)
    assert result["motion_detected"] is True
    assert result["contact_open"] is True
    assert result["contact_timeout"] is True
    assert result["is_light"] is True
    assert result["button_count"] == 2
    assert result["battery"] is None
    assert result["tested"] is None


def test_process_wocontact_uses_data_when_mfr_missing() -> None:
    """Long service data lets the parser succeed without mfr_data."""
    data = b"d@d\x05\x00u\x00\xf8\x12"
    result = process_wocontact(data, None)
    assert result["battery"] == 100
    assert result["motion_detected"] is True
    assert result["contact_open"] is True
    assert result["contact_timeout"] is True
    assert result["is_light"] is True
    assert result["button_count"] == 2
