"""
Tests for the testing utilities.
"""

import json

import pytest

from a2a_lite import Agent, AgentTestClient
from a2a_lite.testing import TestResult


@pytest.fixture
def simple_agent():
    """Create a simple agent for testing."""
    agent = Agent(name="TestAgent", description="For testing")

    @agent.skill("add")
    async def add(a: int, b: int) -> int:
        return a + b

    @agent.skill("greet")
    async def greet(name: str = "World") -> str:
        return f"Hello, {name}!"

    @agent.skill("get_dict")
    async def get_dict(key: str) -> dict:
        return {"key": key, "value": 42}

    return agent


def test_test_client_call(simple_agent):
    """Test calling a skill through TestClient."""
    client = AgentTestClient(simple_agent)
    result = client.call("add", a=2, b=3)
    assert result == 5


def test_test_client_with_defaults(simple_agent):
    """Test calling skill with default parameters."""
    client = AgentTestClient(simple_agent)
    result = client.call("greet")
    assert result == "Hello, World!"


def test_test_client_with_params(simple_agent):
    """Test calling skill with custom parameters."""
    client = AgentTestClient(simple_agent)
    result = client.call("greet", name="Alice")
    assert result == "Hello, Alice!"


def test_test_client_dict_result(simple_agent):
    """Test skill returning dict."""
    client = AgentTestClient(simple_agent)
    result = client.call("get_dict", key="test")
    assert result == {"key": "test", "value": 42}


def test_test_client_list_skills(simple_agent):
    """Test listing skills."""
    client = AgentTestClient(simple_agent)
    skills = client.list_skills()
    assert "add" in skills
    assert "greet" in skills
    assert "get_dict" in skills


def test_test_client_get_agent_card(simple_agent):
    """Test fetching agent card."""
    client = AgentTestClient(simple_agent)
    card = client.get_agent_card()
    assert card["name"] == "TestAgent"
    assert len(card["skills"]) == 3


class TestTestResult:
    def test_data_property(self):
        result = TestResult(_data=42, _text="42", raw_response={})
        assert result.data == 42

    def test_text_property(self):
        result = TestResult(_data="hello", _text="hello", raw_response={})
        assert result.text == "hello"

    def test_json_method(self):
        result = TestResult(_data={"key": "value"}, _text='{"key": "value"}', raw_response={})
        assert result.json() == {"key": "value"}

    def test_json_invalid(self):
        result = TestResult(_data="not json", _text="not json", raw_response={})
        with pytest.raises(json.JSONDecodeError):
            result.json()

    def test_eq_with_value(self):
        result = TestResult(_data=42, _text="42", raw_response={})
        assert result == 42
        assert result != 43

    def test_eq_with_string(self):
        result = TestResult(_data="hello", _text="hello", raw_response={})
        assert result == "hello"

    def test_eq_with_dict(self):
        result = TestResult(_data={"key": "value"}, _text='{"key": "value"}', raw_response={})
        assert result == {"key": "value"}

    def test_eq_with_test_result(self):
        r1 = TestResult(_data=42, _text="42", raw_response={})
        r2 = TestResult(_data=42, _text="42", raw_response={})
        assert r1 == r2

    def test_repr(self):
        result = TestResult(_data=42, _text="42", raw_response={})
        assert "42" in repr(result)

    def test_raw_response(self):
        resp = {"result": {"parts": [{"kind": "text", "text": "hi"}]}}
        result = TestResult(_data="hi", _text="hi", raw_response=resp)
        assert result.raw_response == resp


class TestAgentTestClientStream:
    def test_stream_async_generator(self):
        agent = Agent(name="Test", description="Test")

        @agent.skill("count", streaming=True)
        async def count(limit: int = 3):
            for i in range(limit):
                yield i

        client = AgentTestClient(agent)
        results = client.stream("count", limit=3)
        assert results == [0, 1, 2]

    def test_stream_sync_generator(self):
        agent = Agent(name="Test", description="Test")

        @agent.skill("words", streaming=True)
        def words(text: str = "hello world"):
            yield from text.split()

        client = AgentTestClient(agent)
        results = client.stream("words", text="a b c")
        assert results == ["a", "b", "c"]

    def test_stream_unknown_skill(self):
        from a2a_lite.testing import TestClientError

        agent = Agent(name="Test", description="Test")
        client = AgentTestClient(agent)

        with pytest.raises(TestClientError, match="Unknown skill"):
            client.stream("nonexistent")


class TestAsyncAgentTestClient:
    """Tests for AsyncAgentTestClient using httpx.ASGITransport (compatible with httpx >= 0.28)."""

    def test_creation(self):
        from a2a_lite import AsyncAgentTestClient

        agent = Agent(name="Test", description="Test")

        @agent.skill("add")
        async def add(a: int, b: int) -> int:
            return a + b

        client = AsyncAgentTestClient(agent)
        assert client.agent is agent

    @pytest.mark.asyncio
    async def test_async_call(self):
        from a2a_lite import AsyncAgentTestClient

        agent = Agent(name="Test", description="Test")

        @agent.skill("add")
        async def add(a: int, b: int) -> int:
            return a + b

        client = AsyncAgentTestClient(agent)
        result = await client.call("add", a=2, b=3)
        assert result == 5
        await client.close()
