"""Tests for NMEA wire protocol: checksum, framing, validation."""

from lc29h.protocol import (
    ACK_SUCCESS,
    compute_checksum,
    frame_command,
    parse_ack,
    parse_response,
    validate_checksum,
)


class TestChecksum:
    def test_simple_checksum(self):
        # PAIR050,1000 should XOR all chars
        cs = compute_checksum("PAIR050,1000")
        assert len(cs) == 2
        assert cs == cs.upper()

    def test_checksum_deterministic(self):
        assert compute_checksum("PAIR003") == compute_checksum("PAIR003")

    def test_different_inputs_different_checksums(self):
        assert compute_checksum("PAIR003") != compute_checksum("PAIR004")

    def test_known_checksum(self):
        # PAIR003: P^A^I^R^0^0^3 = 0x50^0x41^0x49^0x52^0x30^0x30^0x33 = 0x39
        cs = compute_checksum("PAIR003")
        assert cs == "39"


class TestFrameCommand:
    def test_basic_framing(self):
        result = frame_command("PAIR003")
        assert result.startswith(b"$")
        assert result.endswith(b"\r\n")
        assert b"*" in result

    def test_framing_is_ascii(self):
        result = frame_command("PAIR050,1000")
        assert result == result.decode("ascii").encode("ascii")

    def test_framing_includes_checksum(self):
        result = frame_command("PAIR003")
        text = result.decode("ascii")
        assert text == "$PAIR003*39\r\n"


class TestValidateChecksum:
    def test_valid_sentence(self):
        assert validate_checksum("$PAIR003*39") is True

    def test_valid_with_crlf(self):
        assert validate_checksum("$PAIR003*39\r\n") is True

    def test_invalid_checksum(self):
        assert validate_checksum("$PAIR003*FF") is False

    def test_no_dollar_sign(self):
        assert validate_checksum("PAIR003*04") is False

    def test_no_asterisk(self):
        assert validate_checksum("$PAIR003") is False


class TestParseAck:
    def test_success_ack(self):
        # Need to compute a valid checksum for $PAIR001,066,0
        body = "PAIR001,066,0"
        cs = compute_checksum(body)
        line = f"$PAIR001,066,0*{cs}"
        cmd_id, result = parse_ack(line)
        assert cmd_id == "066"
        assert result == ACK_SUCCESS

    def test_failure_ack(self):
        body = "PAIR001,066,1"
        cs = compute_checksum(body)
        line = f"$PAIR001,066,1*{cs}"
        cmd_id, result = parse_ack(line)
        assert cmd_id == "066"
        assert result == 1

    def test_invalid_checksum_raises(self):
        import pytest

        with pytest.raises(ValueError):
            parse_ack("$PAIR001,066,0*FF")


class TestParseResponse:
    def test_pair_response(self):
        body = "PAIR021,LC29HDANR"
        cs = compute_checksum(body)
        line = f"${body}*{cs}"
        sentence_id, fields = parse_response(line)
        assert sentence_id == "PAIR021"
        assert fields == ["LC29HDANR"]

    def test_nmea_gga(self):
        body = "GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,47.0,M,,"
        cs = compute_checksum(body)
        line = f"${body}*{cs}"
        sentence_id, fields = parse_response(line)
        assert sentence_id == "GPGGA"
        assert fields[0] == "123519"
