"""Test MCP client helpers: headers, error mapping, content parsing."""

import pytest
from mcpbundles.mcp_client import (
    _build_headers,
    _extract_result,
    _parse_sse_result,
    _parse_content_blocks,
    ConnectionError,
    ToolCallError,
    extract_text,
    extract_json,
)
from mcpbundles.mcp_client import CallToolResult, TextContent, ImageContent


class TestBuildHeaders:
    def test_api_key(self):
        h = _build_headers("mb_test_key_123")
        assert h["X-API-Key"] == "mb_test_key_123"
        assert "Authorization" not in h
        assert h["Accept"] == "application/json, text/event-stream"

    def test_bearer_token(self):
        h = _build_headers("eyJtoken.stuff.here")
        assert h["Authorization"] == "Bearer eyJtoken.stuff.here"
        assert "X-API-Key" not in h


class TestParseSSEResult:
    def test_basic_sse(self):
        sse = 'event: message\ndata: {"jsonrpc":"2.0","id":2,"result":{"tools":[]}}\n\n'
        result = _parse_sse_result(sse, 2)
        assert result == {"tools": []}

    def test_ignores_notifications(self):
        sse = (
            'event: message\ndata: {"jsonrpc":"2.0","method":"notifications/progress"}\n\n'
            'event: message\ndata: {"jsonrpc":"2.0","id":3,"result":{"ok":true}}\n\n'
        )
        result = _parse_sse_result(sse, 3)
        assert result == {"ok": True}

    def test_error_in_sse(self):
        sse = 'data: {"jsonrpc":"2.0","id":1,"error":{"message":"bad request"}}\n\n'
        with pytest.raises(ConnectionError, match="bad request"):
            _parse_sse_result(sse, 1)

    def test_no_matching_id(self):
        sse = 'data: {"jsonrpc":"2.0","id":99,"result":{}}\n\n'
        with pytest.raises(ConnectionError, match="No matching response"):
            _parse_sse_result(sse, 1)


class TestParseContentBlocks:
    def test_text_block(self):
        blocks = _parse_content_blocks([{"type": "text", "text": "hello"}])
        assert len(blocks) == 1
        assert isinstance(blocks[0], TextContent)
        assert blocks[0].text == "hello"

    def test_image_block(self):
        blocks = _parse_content_blocks([{"type": "image", "data": "abc", "mimeType": "image/png"}])
        assert len(blocks) == 1
        assert isinstance(blocks[0], ImageContent)
        assert blocks[0].data == "abc"
        assert blocks[0].mimeType == "image/png"

    def test_mixed_blocks(self):
        blocks = _parse_content_blocks([
            {"type": "text", "text": "caption"},
            {"type": "image", "data": "xyz", "mimeType": "image/jpeg"},
        ])
        assert len(blocks) == 2
        assert isinstance(blocks[0], TextContent)
        assert isinstance(blocks[1], ImageContent)


class TestToolCallError:
    def test_message(self):
        exc = ToolCallError("tool failed")
        assert str(exc) == "tool failed"

    def test_content_preserved(self):
        content = [TextContent(type="text", text="details")]
        exc = ToolCallError("fail", content=content)
        assert exc.content == content


class TestExtractText:
    def test_single_text(self):
        result = CallToolResult(
            content=[TextContent(type="text", text="hello")],
            isError=False,
        )
        assert extract_text(result) == "hello"

    def test_multiple_text(self):
        result = CallToolResult(
            content=[
                TextContent(type="text", text="line1"),
                TextContent(type="text", text="line2"),
            ],
            isError=False,
        )
        assert extract_text(result) == "line1\nline2"

    def test_mixed_content_skips_images(self):
        result = CallToolResult(
            content=[
                TextContent(type="text", text="text"),
                ImageContent(type="image", data="abc", mimeType="image/png"),
            ],
            isError=False,
        )
        assert extract_text(result) == "text"

    def test_empty_content(self):
        result = CallToolResult(content=[], isError=False)
        assert extract_text(result) == ""


class TestExtractJson:
    def test_valid_json(self):
        result = CallToolResult(
            content=[TextContent(type="text", text='{"key": "value"}')],
            isError=False,
        )
        assert extract_json(result) == {"key": "value"}

    def test_invalid_json_returns_text(self):
        result = CallToolResult(
            content=[TextContent(type="text", text="plain text")],
            isError=False,
        )
        assert extract_json(result) == "plain text"
