"""Unit tests: SSEDecoder — parsing raw SSE byte streams into SSEEvent objects."""

from seaart._transport_sse import SSEDecoder, SSEEvent


# ── Basic parsing ───────────────────────────────────────────────────────────


class TestSSEDecoderBasic:
    def test_simple_data_event(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b'data: {"id": 1}\n\n')
        assert len(events) == 1
        assert events[0].data == '{"id": 1}'
        assert events[0].event == "message"

    def test_custom_event_type(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"event: chunk\ndata: hello\n\n")
        assert len(events) == 1
        assert events[0].event == "chunk"
        assert events[0].data == "hello"

    def test_id_field(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"id: 42\ndata: test\n\n")
        assert events[0].id == "42"

    def test_retry_field(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"retry: 3000\ndata: test\n\n")
        assert events[0].retry == 3000

    def test_retry_non_integer_ignored(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"retry: abc\ndata: test\n\n")
        assert events[0].retry is None


# ── Multi-line data ─────────────────────────────────────────────────────────


class TestSSEDecoderMultiLine:
    def test_multi_line_data(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"data: line1\ndata: line2\ndata: line3\n\n")
        assert len(events) == 1
        assert events[0].data == "line1\nline2\nline3"

    def test_multiple_events_in_one_chunk(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"data: first\n\ndata: second\n\n")
        assert len(events) == 2
        assert events[0].data == "first"
        assert events[1].data == "second"

    def test_event_resets_between_events(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"event: chunk\ndata: one\n\ndata: two\n\n")
        assert events[0].event == "chunk"
        assert events[1].event == "message"  # reset to default


# ── Incremental feeding ─────────────────────────────────────────────────────


class TestSSEDecoderIncremental:
    def test_split_across_chunks(self) -> None:
        dec = SSEDecoder()
        assert dec.feed(b"data: hel") == []
        assert dec.feed(b"lo\n") == []
        events = dec.feed(b"\n")
        assert len(events) == 1
        assert events[0].data == "hello"

    def test_byte_by_byte(self) -> None:
        dec = SSEDecoder()
        raw = b"data: x\n\n"
        events: list[SSEEvent] = []
        for byte in raw:
            events.extend(dec.feed(bytes([byte])))
        assert len(events) == 1
        assert events[0].data == "x"

    def test_no_events_from_incomplete(self) -> None:
        dec = SSEDecoder()
        assert dec.feed(b"data: partial") == []
        assert dec.feed(b"\n") == []  # still no blank line


# ── Edge cases ──────────────────────────────────────────────────────────────


class TestSSEDecoderEdgeCases:
    def test_comment_lines_ignored(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b": this is a comment\ndata: real\n\n")
        assert len(events) == 1
        assert events[0].data == "real"

    def test_crlf_line_endings(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"data: crlf\r\n\r\n")
        assert len(events) == 1
        assert events[0].data == "crlf"

    def test_empty_data_field(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"data:\n\n")
        assert len(events) == 1
        assert events[0].data == ""

    def test_data_without_space_after_colon(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"data:nospace\n\n")
        assert len(events) == 1
        assert events[0].data == "nospace"

    def test_field_without_colon(self) -> None:
        dec = SSEDecoder()
        # per SSE spec, field without colon uses empty string as value
        events = dec.feed(b"data\n\n")
        assert len(events) == 1
        assert events[0].data == ""

    def test_blank_line_without_data_produces_no_event(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"\n\n")
        assert events == []

    def test_only_comments_produce_no_events(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b": comment1\n: comment2\n\n")
        assert events == []

    def test_buffer_overflow_clears_state(self) -> None:
        dec = SSEDecoder()
        # Feed > 2MB to trigger overflow protection
        huge = b"data: " + b"x" * 2_000_001 + b"\n"
        events = dec.feed(huge)
        assert events == []
        # Decoder should recover after overflow
        events = dec.feed(b"data: ok\n\n")
        assert len(events) == 1
        assert events[0].data == "ok"

    def test_unknown_field_ignored(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"foo: bar\ndata: real\n\n")
        assert len(events) == 1
        assert events[0].data == "real"

    def test_id_and_retry_reset_between_events(self) -> None:
        dec = SSEDecoder()
        events = dec.feed(b"id: 1\nretry: 5000\ndata: first\n\ndata: second\n\n")
        assert events[0].id == "1"
        assert events[0].retry == 5000
        assert events[1].id is None
        assert events[1].retry is None
