"""Unit tests for async document operations."""

import httpx
import pytest
import respx

from pinecone._internal.http import AsyncHTTPClient, HTTPConfig
from pinecone.async_index.documents import AsyncDocuments


@pytest.mark.asyncio()
@respx.mock
async def test_async_upsert_success():
    """Test successful async document upsert."""
    respx.post("https://test.io/namespaces/my-ns/documents/upsert").mock(
        return_value=httpx.Response(200, json={"upserted_count": 2})
    )

    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    response = await documents.upsert(
        namespace="my-ns",
        documents=[
            {"_id": "doc1", "title": "Hello"},
            {"_id": "doc2", "title": "World"},
        ],
    )

    assert response.upserted_count == 2


@pytest.mark.asyncio()
@respx.mock
async def test_async_upsert_validates_empty_namespace():
    """Test that empty namespace raises ValueError."""
    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    with pytest.raises(ValueError, match="namespace"):
        await documents.upsert(namespace="", documents=[{"_id": "doc1"}])


@pytest.mark.asyncio()
@respx.mock
async def test_async_upsert_validates_empty_documents():
    """Test that empty documents list raises ValueError."""
    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    with pytest.raises(ValueError, match="documents must not be empty"):
        await documents.upsert(namespace="my-ns", documents=[])


@pytest.mark.asyncio()
@respx.mock
async def test_async_upsert_validates_missing_id():
    """Test that document without _id raises ValueError."""
    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    with pytest.raises(ValueError, match="missing required '_id' field"):
        await documents.upsert(namespace="my-ns", documents=[{"title": "No ID"}])


@pytest.mark.asyncio()
@respx.mock
async def test_async_upsert_validates_non_string_id():
    """Test that non-string _id raises TypeError."""
    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    with pytest.raises(TypeError, match="non-string '_id': int"):
        await documents.upsert(
            namespace="my-ns",
            documents=[
                {"_id": 123, "text": "Numeric ID"},
            ],
        )


@pytest.mark.asyncio()
@respx.mock
async def test_async_upsert_validates_empty_id():
    """Test that empty string _id raises ValueError."""
    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    with pytest.raises(ValueError, match="empty '_id'"):
        await documents.upsert(
            namespace="my-ns",
            documents=[
                {"_id": "", "text": "Empty ID"},
            ],
        )


@pytest.mark.asyncio()
@respx.mock
async def test_async_upsert_validates_duplicate_ids():
    """Test that duplicate _ids in batch raise ValueError."""
    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    with pytest.raises(ValueError, match="duplicate '_id': 'doc1'"):
        await documents.upsert(
            namespace="my-ns",
            documents=[
                {"_id": "doc1", "text": "First"},
                {"_id": "doc2", "text": "Second"},
                {"_id": "doc1", "text": "Duplicate!"},
            ],
        )


@pytest.mark.asyncio()
@respx.mock
async def test_async_upsert_validates_batch_size_exceeds_limit():
    """Test that > 1000 documents raises ValueError."""
    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    # Create 1001 documents
    large_batch = [{"_id": f"doc{i}", "text": "test"} for i in range(1001)]

    with pytest.raises(ValueError, match=r"documents.*1000"):
        await documents.upsert(namespace="my-ns", documents=large_batch)


@pytest.mark.asyncio()
@respx.mock
async def test_async_upsert_validates_batch_size_at_limit():
    """Test that exactly 1000 documents is accepted."""
    respx.post("https://test.io/namespaces/my-ns/documents/upsert").mock(
        return_value=httpx.Response(200, json={"upserted_count": 1000})
    )

    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    # Create exactly 1000 documents
    max_batch = [{"_id": f"doc{i}", "text": "test"} for i in range(1000)]

    response = await documents.upsert(namespace="my-ns", documents=max_batch)
    assert response.upserted_count == 1000


@pytest.mark.asyncio()
@respx.mock
async def test_async_search_success():
    """Test successful async document search."""
    respx.post("https://test.io/namespaces/my-ns/documents/search").mock(
        return_value=httpx.Response(
            200,
            json={
                "documents": [{"_id": "doc1", "score": 0.95}],
                "usage": {"read_units": 5},
            },
        )
    )

    client = AsyncHTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = AsyncDocuments(http=client, base_url="https://test.io")

    response = await documents.search(
        namespace="my-ns",
        top_k=10,
        score_by=[{"type": "text", "field": "title", "text_query": "hello"}],
    )

    assert len(response.documents) == 1
    assert response.documents[0].id == "doc1"
