"""Comprehensive tests for async AsyncMiruvorClient."""
from unittest.mock import AsyncMock, patch

import pytest

from miruvor import AsyncMiruvorClient, AuthenticationError

from .conftest import create_mock_response


@pytest.fixture
async def async_client():
    """Create async test client."""
    client = AsyncMiruvorClient(
        base_url="https://api.example.com",
        api_key="test-key",
        token="test-token",
    )
    yield client
    await client.close()


@pytest.mark.asyncio
class TestAsyncStoreMethod:
    """Tests for async store() method."""

    async def test_store_success(self, async_client, mock_store_response):
        """Test successful async store operation."""
        with patch.object(
            async_client.client, "request", new_callable=AsyncMock
        ) as mock_req:
            mock_req.return_value = create_mock_response(
                200, mock_store_response
            )

            response = await async_client.store(text="Test memory")

            assert response.memory_id == "mem_123abc"
            assert response.storage_time_ms == 15.5

    async def test_store_batch_concurrent(self, async_client, mock_store_response):
        """Test batch store with concurrency control."""
        with patch.object(
            async_client.client, "request", new_callable=AsyncMock
        ) as mock_req:
            mock_req.return_value = create_mock_response(
                200, mock_store_response
            )

            memories = [{"text": f"Memory {i}"} for i in range(20)]

            responses = await async_client.store_batch(
                memories, max_concurrent=5
            )

            assert len(responses) == 20
            assert all(r.memory_id == "mem_123abc" for r in responses)


@pytest.mark.asyncio
class TestAsyncRetrieveMethod:
    """Tests for async retrieve() method."""

    async def test_retrieve_success(self, async_client, mock_retrieve_response):
        """Test successful async retrieve operation."""
        with patch.object(
            async_client.client, "request", new_callable=AsyncMock
        ) as mock_req:
            mock_req.return_value = create_mock_response(
                200, mock_retrieve_response
            )

            response = await async_client.retrieve(query="test query")

            assert response.num_results == 2
            assert response.results[0].score == 0.95


@pytest.mark.asyncio
class TestAsyncContextManager:
    """Tests for async context manager."""

    async def test_async_context_manager(self, mock_store_response):
        """Test async context manager creates and closes client."""
        async with AsyncMiruvorClient(
            base_url="https://api.example.com",
            api_key="test-key",
        ) as client:
            with patch.object(
                client.client, "request", new_callable=AsyncMock
            ) as mock_req:
                mock_req.return_value = create_mock_response(
                    200, mock_store_response
                )
                response = await client.store(text="Test")
                assert response.memory_id == "mem_123abc"

        assert client._client is None or client._client.is_closed


@pytest.mark.asyncio
class TestAsyncErrorHandling:
    """Tests for async error handling."""

    async def test_authentication_error(self, async_client):
        """Test async 401 raises AuthenticationError."""
        with patch.object(
            async_client.client, "request", new_callable=AsyncMock
        ) as mock_req:
            mock_req.return_value = create_mock_response(
                401,
                {"detail": "Invalid API key"},
            )

            with pytest.raises(AuthenticationError):
                await async_client.store(text="Test")
