"""Tests for the aqoon Python SDK client."""

import httpx
import pytest

from aqoon import (
    Aqoon,
    AuthenticationError,
    NotFoundError,
    RateLimitError,
    ValidationError,
)


def _mock_transport(responses: dict):
    """Create a mock transport that returns predefined responses."""

    def handler(request: httpx.Request):
        path = request.url.path
        method = request.method

        key = f"{method} {path}"
        if key in responses:
            status, body = responses[key]
            return httpx.Response(status, json=body)

        # Try path-only match
        if path in responses:
            status, body = responses[path]
            return httpx.Response(status, json=body)

        return httpx.Response(404, json={"error": "Not found"})

    return httpx.MockTransport(handler)


def _make_client(responses: dict) -> Aqoon:
    """Create an Aqoon client with mocked HTTP transport."""
    client = Aqoon(api_key="aqn_test_key_12345678901234567890")
    client._http = httpx.Client(
        base_url="https://aqoon.ai",
        headers={"Authorization": "Bearer aqn_test"},
        transport=_mock_transport(responses),
    )
    return client


class TestSearch:
    def test_search_returns_results(self):
        client = _make_client(
            {
                "POST /api/v1/search/": (
                    200,
                    {
                        "query": "test",
                        "count": 1,
                        "results": [
                            {
                                "title": "Doc",
                                "content": "Hello",
                                "score": 0.9,
                                "document_id": "abc",
                                "collection_name": "Coll",
                                "tags": [],
                            },
                        ],
                    },
                ),
            },
        )
        resp = client.search("test")
        assert resp["count"] == 1
        assert resp["results"][0]["title"] == "Doc"

    def test_search_with_collection(self):
        client = _make_client(
            {
                "POST /api/v1/search/": (
                    200,
                    {"query": "test", "count": 0, "results": []},
                ),
            },
        )
        resp = client.search("test", collection="my-docs", limit=10)
        assert resp["count"] == 0


class TestCollections:
    def test_list_collections(self):
        client = _make_client(
            {
                "/api/v1/collections/": (
                    200,
                    {
                        "count": 1,
                        "next": None,
                        "previous": None,
                        "results": [{"uuid": "abc", "name": "Test", "slug": "test"}],
                    },
                ),
            },
        )
        colls = client.list_collections()
        assert len(colls) == 1
        assert colls[0]["name"] == "Test"

    def test_get_collection(self):
        client = _make_client(
            {
                "/api/v1/collections/abc/": (200, {"uuid": "abc", "name": "Test"}),
            },
        )
        coll = client.get_collection("abc")
        assert coll["uuid"] == "abc"


class TestDocuments:
    def test_list_documents(self):
        client = _make_client(
            {
                "/api/v1/documents/": (
                    200,
                    {
                        "count": 1,
                        "next": None,
                        "results": [{"uuid": "doc1", "title": "My Doc"}],
                    },
                ),
            },
        )
        docs = client.list_documents()
        assert len(docs) == 1

    def test_get_document(self):
        client = _make_client(
            {
                "/api/v1/documents/doc1/": (
                    200,
                    {
                        "uuid": "doc1",
                        "title": "My Doc",
                        "content_text": "Hello world",
                        "chunks": [],
                    },
                ),
            },
        )
        doc = client.get_document("doc1")
        assert doc["title"] == "My Doc"
        assert doc["content_text"] == "Hello world"


class TestErrorHandling:
    def test_401_raises_authentication_error(self):
        client = _make_client(
            {
                "POST /api/v1/search/": (401, {"error": "Invalid API key."}),
            },
        )
        with pytest.raises(AuthenticationError, match="Invalid API key"):
            client.search("test")

    def test_404_raises_not_found(self):
        client = _make_client(
            {
                "/api/v1/documents/missing/": (404, {"error": "Not found"}),
            },
        )
        with pytest.raises(NotFoundError):
            client.get_document("missing")

    def test_400_raises_validation_error(self):
        client = _make_client(
            {
                "POST /api/v1/search/": (
                    400,
                    {
                        "error": "Query is required",
                        "fields": {"query": ["This field is required."]},
                    },
                ),
            },
        )
        with pytest.raises(ValidationError) as exc_info:
            client.search("")
        assert exc_info.value.errors == {"query": ["This field is required."]}

    def test_429_raises_rate_limit_error(self):
        transport = httpx.MockTransport(
            lambda req: httpx.Response(
                429,
                json={"error": "Rate limit exceeded"},
                headers={"Retry-After": "60"},
            ),
        )
        client = Aqoon(api_key="aqn_test_key_12345678901234567890")
        client._http = httpx.Client(base_url="https://aqoon.ai", transport=transport)

        with pytest.raises(RateLimitError) as exc_info:
            client.search("test")
        assert exc_info.value.retry_after == 60.0


class TestInit:
    def test_rejects_invalid_api_key(self):
        with pytest.raises(ValueError, match="aqn_"):
            Aqoon(api_key="invalid_key")

    def test_rejects_empty_api_key(self):
        with pytest.raises(ValueError):
            Aqoon(api_key="")

    def test_context_manager(self):
        with Aqoon(api_key="aqn_test_key_12345678901234567890") as client:
            assert client is not None
