"""Unit tests for event dataclass wire serialization."""

from navi.core.events import (
    AIHelperTokensUsed,
    CompressionStarted,
    ContextCompressed,
    PlanReady,
    PlanningDebugData,
    PlanningStatus,
    ProfileSwitched,
    RecallUpdate,
    StreamEnd,
    StreamStopped,
    SubagentComplete,
    TextDelta,
    ThinkingDelta,
    ThinkingEnd,
    TodoUpdated,
    ToolEvent,
    ToolStarted,
    TurnThinking,
)


class TestToolStarted:
    def test_to_wire(self):
        ev = ToolStarted(tool_name="fs", arguments={"action": "read"})
        assert ev.to_wire() == {
            "type": "tool_started",
            "tool": "fs",
            "args": {"action": "read"},
            "is_subagent": False,
            "metadata": {},
            "tool_call_id": "",
        }

    def test_to_wire_carries_metadata(self):
        ev = ToolStarted(tool_name="todo", arguments={"op": "update"}, metadata={"step_text": "run tests"})
        assert ev.to_wire()["metadata"] == {"step_text": "run tests"}

    def test_to_wire_subagent(self):
        ev = ToolStarted(tool_name="spawn_agent", arguments={}, is_subagent=True)
        assert ev.to_wire()["is_subagent"] is True


class TestToolEvent:
    def test_to_wire(self):
        ev = ToolEvent(
            tool_name="fs",
            arguments={"path": "/tmp"},
            result="file contents",
            success=True,
            metadata={"size": 42},
        )
        assert ev.to_wire() == {
            "type": "tool_call",
            "tool": "fs",
            "args": {"path": "/tmp"},
            "result": "file contents",
            "success": True,
            "is_subagent": False,
            "metadata": {"size": 42},
            "tool_call_id": "",
        }


class TestTextDelta:
    def test_to_wire(self):
        assert TextDelta(delta="hello").to_wire() == {"type": "stream_delta", "delta": "hello"}


class TestThinkingDelta:
    def test_to_wire(self):
        assert ThinkingDelta(delta="hmm").to_wire() == {"type": "thinking_delta", "delta": "hmm"}


class TestThinkingEnd:
    def test_to_wire(self):
        assert ThinkingEnd().to_wire() == {"type": "thinking_end"}


class TestStreamEnd:
    def test_to_wire(self):
        ev = StreamEnd(
            full_content="done",
            context_tokens=150,
            max_context_tokens=8192,
            elapsed_seconds=1.5,
            tool_call_count=2,
            token_count=150,
        )
        wire = ev.to_wire()
        assert wire["type"] == "stream_end"
        assert wire["content"] == "done"
        assert wire["context_tokens"] == 150
        assert wire["tool_call_count"] == 2


class TestStreamStopped:
    def test_to_wire(self):
        assert StreamStopped().to_wire() == {"type": "stream_stopped"}


class TestContextCompressed:
    def test_to_wire(self):
        ev = ContextCompressed(messages_before=10, messages_after=3, summary="summary text")
        wire = ev.to_wire()
        assert wire["type"] == "context_compressed"
        assert wire["messages_before"] == 10
        assert wire["messages_after"] == 3
        assert wire["summary"] == "summary text"
        assert wire["context_tokens"] is None


class TestProfileSwitched:
    def test_to_wire(self):
        ev = ProfileSwitched(profile_id="dev", profile_name="Developer")
        assert ev.to_wire() == {
            "type": "profile_switched",
            "profile_id": "dev",
            "profile_name": "Developer",
        }


class TestPlanningStatus:
    def test_to_wire(self):
        ev = PlanningStatus(phase=1, label="Working on it...")
        assert ev.to_wire() == {
            "type": "planning_status",
            "phase": 1,
            "label": "Working on it...",
            "is_subagent": False,
        }


class TestPlanReady:
    def test_to_wire(self):
        ev = PlanReady(plan="1. Do thing")
        wire = ev.to_wire()
        assert wire["type"] == "plan_ready"
        assert wire["plan"] == "1. Do thing"
        assert wire["is_subagent"] is False


class TestTurnThinking:
    def test_to_wire(self):
        ev = TurnThinking(thinking="reasoning...", is_subagent=True)
        wire = ev.to_wire()
        assert wire["type"] == "turn_thinking"
        assert wire["thinking"] == "reasoning..."
        assert wire["is_subagent"] is True


class TestCompressionStarted:
    def test_to_wire(self):
        ev = CompressionStarted(context_tokens=5000, max_context_tokens=8192)
        wire = ev.to_wire()
        assert wire["type"] == "compression_started"
        assert wire["context_tokens"] == 5000
        assert wire["max_context_tokens"] == 8192


class TestInternalEvents:
    """Internal events must NOT serialize to the wire."""

    def test_subagent_complete(self):
        assert SubagentComplete(token_count=42).to_wire() is None

    def test_planning_debug_data(self):
        assert PlanningDebugData(log={"phases": {}}).to_wire() is None

    def test_ai_helper_tokens_used(self):
        ev = AIHelperTokensUsed(prompt_tokens=10, completion_tokens=20)
        assert ev.to_wire() is None
        assert ev.total == 30


class TestTodoUpdated:
    def test_to_wire_empty(self):
        ev = TodoUpdated(session_id="sess1")
        assert ev.to_wire() == {"type": "todo_updated", "session_id": "sess1", "tasks": []}

    def test_to_wire_with_tasks(self):
        tasks = [
            {"index": 1, "text": "step one", "status": "done", "validation": "ran tests"},
            {"index": 2, "text": "step two", "status": "in_progress", "validation": ""},
        ]
        ev = TodoUpdated(session_id="sess1", tasks=tasks)
        wire = ev.to_wire()
        assert wire["type"] == "todo_updated"
        assert wire["session_id"] == "sess1"
        assert wire["tasks"] == tasks
        assert len(wire["tasks"]) == 2


class TestRecallUpdate:
    def test_to_wire_defaults_message_none(self):
        ev = RecallUpdate(session_id="s1", action="scheduled")
        wire = ev.to_wire()
        assert wire["type"] == "recall_update"
        assert wire["session_id"] == "s1"
        assert wire["action"] == "scheduled"
        assert wire["message"] is None

    def test_to_wire_carries_message(self):
        ev = RecallUpdate(
            session_id="s1",
            recall_id="r1",
            call_type="once",
            trigger_at="2026-07-12T18:45:00",
            status="pending",
            action="scheduled",
            message="Read /tmp/build.log and report errors.",
        )
        wire = ev.to_wire()
        assert wire["type"] == "recall_update"
        assert wire["recall_id"] == "r1"
        assert wire["call_type"] == "once"
        assert wire["trigger_at"] == "2026-07-12T18:45:00"
        assert wire["status"] == "pending"
        assert wire["action"] == "scheduled"
        assert wire["message"] == "Read /tmp/build.log and report errors."
