"""Tests for SSE parsing in talk client.

Spec source: talk-streaming-transport.md
Tests SSE event parsing for progressive output.
"""

from anima.shell.cli_commands.talk_streaming import (
    parse_sse_events,
    parse_sse_line,
    SSEEvent,
)


class TestSSELineParsing:
    """Tests for parse_sse_line function."""

    def test_parse_event_field(self):
        """event: field is parsed correctly."""
        assert parse_sse_line("event: chunk") == ("event", "chunk")

    def test_parse_data_field(self):
        """data: field is parsed with JSON content."""
        assert parse_sse_line('data: {"turn": 12}') == ("data", '{"turn": 12}')

    def test_parse_empty_line(self):
        """Empty line returns None tuple."""
        assert parse_sse_line("") == (None, None)

    def test_parse_invalid_line(self):
        """Invalid line (no colon) returns None tuple."""
        assert parse_sse_line("invalid") == (None, None)

    def test_parse_whitespace_handling(self):
        """Whitespace around colon is stripped."""
        assert parse_sse_line("event :  chunk  ") == ("event", "chunk")


class TestSSEEventParsing:
    """Tests for parse_sse_events function."""

    def test_parse_chunk_event(self):
        """Single chunk event is parsed."""
        lines = [
            "event: chunk",
            'data: {"turn": 1, "seq": 1, "chunk": "hello"}',
            "",
        ]
        events = parse_sse_events(lines)

        assert len(events) == 1
        assert events[0].event == "chunk"
        assert events[0].data["turn"] == 1
        assert events[0].data["chunk"] == "hello"

    def test_parse_done_event(self):
        """done event is parsed with all fields."""
        lines = [
            "event: done",
            'data: {"turn": 12, "seq": 42, "stop_reason": "complete", "final_response_chars": 1834}',
            "",
        ]
        events = parse_sse_events(lines)

        assert len(events) == 1
        assert events[0].event == "done"
        assert events[0].data["turn"] == 12
        assert events[0].data["seq"] == 42
        assert events[0].data["stop_reason"] == "complete"

    def test_parse_error_event(self):
        """error event is parsed correctly."""
        lines = [
            "event: error",
            'data: {"turn": 12, "seq": 42, "error": "Something failed", "code": "INTERNAL"}',
            "",
        ]
        events = parse_sse_events(lines)

        assert len(events) == 1
        assert events[0].event == "error"
        assert events[0].data["error"] == "Something failed"
        assert events[0].data["code"] == "INTERNAL"

    def test_parse_multiple_events(self):
        """Multiple events are parsed in sequence."""
        lines = [
            "event: chunk",
            'data: {"turn": 1, "seq": 1, "chunk": "hello"}',
            "",
            "event: chunk",
            'data: {"turn": 1, "seq": 2, "chunk": " world"}',
            "",
            "event: done",
            'data: {"turn": 1, "seq": 3, "stop_reason": "complete"}',
            "",
        ]
        events = parse_sse_events(lines)

        assert len(events) == 3
        assert events[0].event == "chunk"
        assert events[1].event == "chunk"
        assert events[2].event == "done"
        assert events[2].data["stop_reason"] == "complete"

    def test_parse_event_without_trailing_empty_line(self):
        """Event without trailing empty line is still parsed."""
        lines = ["event: chunk", 'data: {"turn": 1, "chunk": "test"}']
        events = parse_sse_events(lines)

        assert len(events) == 1
        assert events[0].event == "chunk"

    def test_parse_multiline_data(self):
        """Multiline data field is concatenated."""
        lines = [
            "event: chunk",
            "data: {",
            'data: "turn": 1,',
            'data: "chunk": "test"}',
            "",
        ]
        events = parse_sse_events(lines)

        assert len(events) == 1
        assert "turn" in events[0].data

    def test_parse_invalid_json_data(self):
        """Invalid JSON still creates event with empty data dict."""
        lines = ["event: chunk", "data: {invalid}", ""]
        events = parse_sse_events(lines)

        assert len(events) == 1
        assert events[0].event == "chunk"
        # Invalid JSON results in empty dict
        assert isinstance(events[0].data, dict)

    def test_parse_empty_event_list(self):
        """Empty input returns empty event list."""
        events = parse_sse_events([])
        assert len(events) == 0

    def test_sse_event_dataclass(self):
        """SSEEvent dataclass fields are accessible."""
        event = SSEEvent(event="chunk", data={"turn": 1, "seq": 2})

        assert event.event == "chunk"
        assert event.data["turn"] == 1
        assert event.data["seq"] == 2

    def test_parse_tool_call_event(self):
        """tool_call event is parsed with tool_name and tool_arg_preview."""
        lines = [
            "event: tool_call",
            'data: {"turn": 1, "tool_name": "bash", "tool_arg_preview": "ls -la"}',
            "",
        ]
        events = parse_sse_events(lines)

        assert len(events) == 1
        assert events[0].event == "tool_call"
        assert events[0].data["tool_name"] == "bash"
        assert events[0].data["tool_arg_preview"] == "ls -la"

    def test_parse_tool_call_event_with_empty_preview(self):
        """tool_call event with empty preview is parsed correctly."""
        lines = [
            "event: tool_call",
            'data: {"turn": 2, "tool_name": "read_file", "tool_arg_preview": ""}',
            "",
        ]
        events = parse_sse_events(lines)

        assert len(events) == 1
        assert events[0].event == "tool_call"
        assert events[0].data["tool_name"] == "read_file"
        assert events[0].data["tool_arg_preview"] == ""

    def test_parse_tool_call_event_without_optional_fields(self):
        """tool_call event without optional fields defaults to empty strings."""
        lines = [
            "event: tool_call",
            'data: {"turn": 3}',
            "",
        ]
        events = parse_sse_events(lines)

        assert len(events) == 1
        assert events[0].event == "tool_call"
        assert events[0].data.get("tool_name", "") == ""
        assert events[0].data.get("tool_arg_preview", "") == ""
