"""Tests for event parsing and the typed event hierarchy."""

from __future__ import annotations

import pytest

from baponi._base import parse_ndjson_line
from baponi._events import (
    KeepaliveEvent,
    OutputEvent,
    ResultEvent,
    StatusEvent,
)
from baponi.exceptions import BaponiError


class TestParseNdjsonLine:
    def test_status_event(self):
        line = '{"type":"status","trace_id":"abc-123","status":"running","seq":1}'
        event = parse_ndjson_line(line)
        assert isinstance(event, StatusEvent)
        assert event.trace_id == "abc-123"
        assert event.status == "running"
        assert event.seq == 1

    def test_output_event(self):
        line = '{"type":"output","stream":"stdout","data":"hello\\n","seq":2}'
        event = parse_ndjson_line(line)
        assert isinstance(event, OutputEvent)
        assert event.stream == "stdout"
        assert event.data == "hello\n"
        assert event.seq == 2

    def test_stderr_output_event(self):
        line = '{"type":"output","stream":"stderr","data":"warn\\n","seq":3}'
        event = parse_ndjson_line(line)
        assert isinstance(event, OutputEvent)
        assert event.stream == "stderr"

    def test_keepalive_event(self):
        line = '{"type":"keepalive","seq":4}'
        event = parse_ndjson_line(line)
        assert isinstance(event, KeepaliveEvent)
        assert event.seq == 4

    def test_result_event(self):
        line = (
            '{"type":"result","trace_id":"abc-123","status":"success",'
            '"result":{"success":true,"stdout":"hi\\n","stderr":"","exit_code":0},'
            '"output_truncated":false,"seq":5}'
        )
        event = parse_ndjson_line(line)
        assert isinstance(event, ResultEvent)
        assert event.trace_id == "abc-123"
        assert event.status == "success"
        assert event.result.stdout == "hi\n"
        assert event.result.exit_code == 0
        assert event.seq == 5

    def test_empty_line_returns_none(self):
        assert parse_ndjson_line("") is None
        assert parse_ndjson_line("   ") is None
        assert parse_ndjson_line("\n") is None

    def test_unknown_event_type_raises(self):
        with pytest.raises(BaponiError, match="Unknown event type"):
            parse_ndjson_line('{"type":"unknown","seq":1}')

    def test_malformed_json_raises(self):
        with pytest.raises(BaponiError, match="Malformed NDJSON"):
            parse_ndjson_line("{not json")

    def test_events_are_frozen(self):
        line = '{"type":"status","trace_id":"abc","status":"running","seq":1}'
        event = parse_ndjson_line(line)
        with pytest.raises(Exception):
            event.status = "changed"  # type: ignore[misc]
