"""End-to-end tests for include_partial_messages option with real Claude API calls.

These tests verify that the SDK properly handles partial message streaming,
including StreamEvent parsing and message interleaving.
"""

from typing import Any

import pytest

from clawd_code_sdk import ClaudeSDKClient
from clawd_code_sdk.models import (
    AssistantMessage,
    ClaudeAgentOptions,
    InitSystemMessage,
    ResultMessage,
    StreamEvent,
    TextBlock,
    ThinkingBlock,
)


@pytest.mark.e2e
@pytest.mark.asyncio
async def test_include_partial_messages_stream_events():
    """Test that include_partial_messages produces StreamEvent messages."""

    options = ClaudeAgentOptions(
        model="claude-sonnet-4-5",
        max_turns=2,
        env={
            "MAX_THINKING_TOKENS": "8000",
        },
    )

    collected_messages: list[Any] = []

    async with ClaudeSDKClient(options) as client:
        # Send a simple prompt that will generate streaming response with thinking
        await client.query("Think of three jokes, then tell one")

        async for message in client.receive_response():
            collected_messages.append(message)

    # Verify we got the expected message types
    message_types = [type(msg).__name__ for msg in collected_messages]

    # Should have InitSystemMessage(init) at the start
    assert message_types[0] == "InitSystemMessage"
    assert isinstance(collected_messages[0], InitSystemMessage)
    assert collected_messages[0].subtype == "init"

    # Should have multiple StreamEvent messages
    stream_events = [msg for msg in collected_messages if isinstance(msg, StreamEvent)]
    assert len(stream_events) > 0, "No StreamEvent messages received"

    # Check for expected StreamEvent types
    event_types = [event.event.get("type") for event in stream_events]
    assert "message_start" in event_types, "No message_start StreamEvent"
    assert "content_block_start" in event_types, "No content_block_start StreamEvent"
    assert "content_block_delta" in event_types, "No content_block_delta StreamEvent"
    assert "content_block_stop" in event_types, "No content_block_stop StreamEvent"
    assert "message_stop" in event_types, "No message_stop StreamEvent"

    # Should have AssistantMessage messages with thinking and text
    assistant_messages = [msg for msg in collected_messages if isinstance(msg, AssistantMessage)]
    assert len(assistant_messages) >= 1, "No AssistantMessage received"

    # Check for thinking block in at least one AssistantMessage
    has_thinking = any(
        any(isinstance(block, ThinkingBlock) for block in msg.content) for msg in assistant_messages
    )
    assert has_thinking, "No ThinkingBlock found in AssistantMessages"

    # Check for text block (the joke) in at least one AssistantMessage
    has_text = any(
        any(isinstance(block, TextBlock) for block in msg.content) for msg in assistant_messages
    )
    assert has_text, "No TextBlock found in AssistantMessages"

    # Should end with ResultMessage
    assert isinstance(collected_messages[-1], ResultMessage)
    assert collected_messages[-1].subtype == "success"


@pytest.mark.e2e
@pytest.mark.asyncio
async def test_include_partial_messages_thinking_deltas():
    """Test that thinking content is streamed incrementally via deltas."""

    options = ClaudeAgentOptions(
        model="claude-sonnet-4-5",
        max_turns=2,
        env={
            "MAX_THINKING_TOKENS": "8000",
        },
    )

    thinking_deltas = []

    async with ClaudeSDKClient(options) as client:
        await client.query("Think step by step about what 2 + 2 equals")

        async for message in client.receive_response():
            if isinstance(message, StreamEvent):
                event = message.event
                if event.get("type") == "content_block_delta":
                    delta = event.get("delta", {})
                    if delta.get("type") == "thinking_delta":
                        thinking_deltas.append(delta.get("thinking", ""))

    # Should have received multiple thinking deltas
    assert len(thinking_deltas) > 0, "No thinking deltas received"

    # Combined thinking should form coherent text
    combined_thinking = "".join(thinking_deltas)
    assert len(combined_thinking) > 10, "Thinking content too short"

    # Should contain some reasoning about the calculation
    assert "2" in combined_thinking.lower(), "Thinking doesn't mention the numbers"
