"""Tests for event handler type contracts.

These tests verify that handlers receive the correct types when processing events:
- Handlers receive TextPart or DataPart, not old TaskMessageContent types
- The Event.content field uses the new simplified types
"""

from unittest.mock import patch

import pytest

from terminaluse.lib.sdk.fastacp.impl.sync_acp import SyncACP
from terminaluse.lib.types.task_context import TaskContext
from terminaluse.types import DataPart, TextPart
from terminaluse.types.event import Event


class TestEventHandlerReceivesCorrectTypes:
    """Tests that event handlers receive the correct content types."""

    @pytest.fixture
    def sync_acp_server(self):
        """Create a SyncACP server instance for testing."""
        with patch.dict("os.environ", {"TERMINALUSE_BASE_URL": ""}):
            return SyncACP.create()

    def test_handler_receives_text_part(self, sync_acp_server):
        """Event handlers receive TextPart for text content."""
        received_content = []

        @sync_acp_server.on_event
        async def handler(ctx: TaskContext, event: Event):
            received_content.append(event.content)
            return {"status": "ok"}

        # Simulate receiving a TextPart event
        text_content = TextPart(text="Hello from user", type="text")

        # Verify TextPart has expected attributes
        assert hasattr(text_content, "text")
        assert text_content.text == "Hello from user"
        assert text_content.type == "text"

    def test_handler_receives_data_part(self, sync_acp_server):
        """Event handlers receive DataPart for data content."""
        received_content = []

        @sync_acp_server.on_event
        async def handler(ctx: TaskContext, event: Event):
            received_content.append(event.content)
            return {"status": "ok"}

        # Simulate receiving a DataPart event
        data_content = DataPart(data={"action": "submit", "values": [1, 2, 3]}, type="data")

        # Verify DataPart has expected attributes
        assert hasattr(data_content, "data")
        assert data_content.data == {"action": "submit", "values": [1, 2, 3]}
        assert data_content.type == "data"

    def test_handler_can_distinguish_content_types(self, sync_acp_server):
        """Handlers can use isinstance to check content type."""

        @sync_acp_server.on_event
        async def handler(ctx: TaskContext, event: Event):
            if isinstance(event.content, TextPart):
                return {"type": "text", "value": event.content.text}
            elif isinstance(event.content, DataPart):
                return {"type": "data", "value": event.content.data}
            else:
                return {"type": "unknown"}

        # Test with TextPart
        text_content = TextPart(text="test")
        assert isinstance(text_content, TextPart)
        assert not isinstance(text_content, DataPart)

        # Test with DataPart
        data_content = DataPart(data={"key": "value"})
        assert isinstance(data_content, DataPart)
        assert not isinstance(data_content, TextPart)


class TestEventContentAccessPatterns:
    """Tests for common patterns when accessing event content."""

    def test_accessing_text_from_text_part(self):
        """Access text content from TextPart."""
        content = TextPart(text="User message here")

        # Correct way to access text
        user_message = content.text
        assert user_message == "User message here"

    def test_accessing_data_from_data_part(self):
        """Access data content from DataPart."""
        content = DataPart(data={"status": "ready", "count": 42})

        # Correct way to access data
        data = content.data
        assert data["status"] == "ready"
        assert data["count"] == 42

    def test_safe_content_access_pattern(self):
        """Pattern for safely handling both content types."""

        def process_event_content(content):
            """Example of safely processing event content."""
            if isinstance(content, TextPart):
                return f"Text: {content.text}"
            elif isinstance(content, DataPart):
                return f"Data: {content.data}"
            else:
                return "Unknown content type"

        # Test with TextPart
        text_result = process_event_content(TextPart(text="Hello"))
        assert text_result == "Text: Hello"

        # Test with DataPart
        data_result = process_event_content(DataPart(data={"key": "value"}))
        assert data_result == "Data: {'key': 'value'}"

    def test_getattr_pattern_for_text(self):
        """Using getattr to safely access text attribute."""
        text_content = TextPart(text="Hello")
        data_content = DataPart(data={"key": "value"})

        # getattr pattern for getting text with default
        text_value = getattr(text_content, "text", None)
        assert text_value == "Hello"

        # Returns None for DataPart (no text attribute)
        no_text = getattr(data_content, "text", None)
        assert no_text is None


class TestEventTypeFromAPIFormat:
    """Tests for parsing Event content from API response format."""

    def test_text_part_from_dict(self):
        """TextPart can be created from API response dict."""
        api_response = {"type": "text", "text": "Hello from API"}

        content = TextPart(**api_response)
        assert content.type == "text"
        assert content.text == "Hello from API"

    def test_data_part_from_dict(self):
        """DataPart can be created from API response dict."""
        api_response = {"type": "data", "data": {"status": "complete"}}

        content = DataPart(**api_response)
        assert content.type == "data"
        assert content.data == {"status": "complete"}

    def test_parsing_event_content_union(self):
        """Parse content based on type discriminator."""

        def parse_content(content_dict):
            """Parse content dict to appropriate type."""
            content_type = content_dict.get("type")
            if content_type == "text":
                return TextPart(**content_dict)
            elif content_type == "data":
                return DataPart(**content_dict)
            else:
                raise ValueError(f"Unknown content type: {content_type}")

        # Parse TextPart
        text_dict = {"type": "text", "text": "Hello"}
        text_content = parse_content(text_dict)
        assert isinstance(text_content, TextPart)
        assert text_content.text == "Hello"

        # Parse DataPart
        data_dict = {"type": "data", "data": [1, 2, 3]}
        data_content = parse_content(data_dict)
        assert isinstance(data_content, DataPart)
        assert data_content.data == [1, 2, 3]
