"""Unit tests for document upsert operation."""

import httpx
import pytest
import respx

from pinecone._internal.http import HTTPClient, HTTPConfig
from pinecone.index.documents import Documents


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

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

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

    assert response.upserted_count == 2


@respx.mock
def test_upsert_validates_empty_namespace():
    """Test that empty namespace raises ValueError."""
    client = HTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = Documents(http=client, base_url="https://test.io")

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


@respx.mock
def test_upsert_validates_empty_documents():
    """Test that empty documents list raises ValueError."""
    client = HTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = Documents(http=client, base_url="https://test.io")

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


@respx.mock
def test_upsert_validates_missing_id():
    """Test that document without _id raises ValueError."""
    client = HTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = Documents(http=client, base_url="https://test.io")

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


@respx.mock
def test_upsert_validates_non_string_id():
    """Test that non-string _id raises TypeError."""
    client = HTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = Documents(http=client, base_url="https://test.io")

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


@respx.mock
def test_upsert_validates_empty_id():
    """Test that empty string _id raises ValueError."""
    client = HTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = Documents(http=client, base_url="https://test.io")

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


@respx.mock
def test_upsert_validates_duplicate_ids():
    """Test that duplicate _ids in batch raise ValueError."""
    client = HTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = Documents(http=client, base_url="https://test.io")

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


@respx.mock
def test_upsert_validates_batch_size_exceeds_limit():
    """Test that > 1000 documents raises ValueError."""
    client = HTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = Documents(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"):
        documents.upsert(namespace="my-ns", documents=large_batch)


@respx.mock
def test_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 = HTTPClient(api_key="test", config=HTTPConfig(http2=False))
    documents = Documents(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 = documents.upsert(namespace="my-ns", documents=max_batch)
    assert response.upserted_count == 1000


@respx.mock
def test_upsert_sends_correct_format():
    """Test that upsert sends documents wrapped in a documents object."""
    route = respx.post("https://test.io/namespaces/my-ns/documents/upsert").mock(
        return_value=httpx.Response(200, json={"upserted_count": 2})
    )

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

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

    # Verify the request was made
    assert route.called
    request = route.calls.last.request

    # Verify the body is JSON with a "documents" wrapper
    import json

    body = json.loads(request.content.decode("utf-8"))

    assert "documents" in body
    assert len(body["documents"]) == 2
    assert body["documents"][0] == {"_id": "doc1", "text": "Hello"}
    assert body["documents"][1] == {"_id": "doc2", "text": "World"}
