"""Tests for the SearchService high-level API."""

from __future__ import annotations

import pytest

from search.backends.memory import MemoryBackend
from search.models import IndexConfig, SearchQuery
from search.service import SearchService


@pytest.fixture()
async def service() -> SearchService:
    backend = MemoryBackend()
    svc = SearchService(backend)
    await svc.create_index(
        IndexConfig(
            name="articles",
            searchable_fields=["title", "body"],
            filterable_fields=["category"],
        )
    )
    return svc


class TestServiceIndexing:
    async def test_index_single_document(self, service: SearchService):
        await service.index_document("articles", {"id": "1", "title": "Hello", "body": "World"})
        result = await service.search("articles", SearchQuery(query="Hello"))
        assert result.total == 1

    async def test_bulk_index(self, service: SearchService):
        docs = [
            {"id": str(i), "title": f"Doc {i}", "body": f"Content {i}"}
            for i in range(25)
        ]
        count = await service.bulk_index("articles", docs)
        assert count == 25
        result = await service.search("articles", SearchQuery(query=""))
        assert result.total == 25

    async def test_delete_document(self, service: SearchService):
        await service.index_document("articles", {"id": "1", "title": "Test"})
        assert await service.delete_document("articles", "1") is True
        assert await service.delete_document("articles", "1") is False

    async def test_delete_nonexistent(self, service: SearchService):
        assert await service.delete_document("articles", "999") is False


class TestServiceSearch:
    async def test_search_with_results(self, service: SearchService):
        await service.index_document("articles", {"id": "1", "title": "Python", "body": "Guide"})
        await service.index_document("articles", {"id": "2", "title": "Rust", "body": "Manual"})
        result = await service.search("articles", SearchQuery(query="Python"))
        assert result.total == 1
        assert result.results[0].id == "1"

    async def test_search_empty_index(self, service: SearchService):
        result = await service.search("articles", SearchQuery(query="anything"))
        assert result.total == 0

    async def test_search_pagination(self, service: SearchService):
        docs = [{"id": str(i), "title": f"Doc {i}", "body": "Content"} for i in range(30)]
        await service.bulk_index("articles", docs)
        page1 = await service.search("articles", SearchQuery(query="", per_page=10, page=1))
        page2 = await service.search("articles", SearchQuery(query="", per_page=10, page=2))
        assert len(page1.results) == 10
        assert len(page2.results) == 10
        ids1 = {r.id for r in page1.results}
        ids2 = {r.id for r in page2.results}
        assert ids1.isdisjoint(ids2)


class TestServiceReindex:
    async def test_reindex_replaces_data(self, service: SearchService):
        await service.index_document("articles", {"id": "old", "title": "Old Doc"})

        async def fetch() -> list[dict]:
            return [
                {"id": "new1", "title": "New One", "body": "Fresh content"},
                {"id": "new2", "title": "New Two", "body": "More content"},
            ]

        count = await service.reindex("articles", fetch)
        assert count == 2

    async def test_reindex_with_empty_fetch(self, service: SearchService):
        await service.index_document("articles", {"id": "1", "title": "Old"})

        async def fetch() -> list[dict]:
            return []

        count = await service.reindex("articles", fetch)
        assert count == 0

    async def test_reindex_returns_count(self, service: SearchService):
        async def fetch() -> list[dict]:
            return [{"id": str(i), "title": f"Item {i}"} for i in range(15)]

        count = await service.reindex("articles", fetch)
        assert count == 15


class TestServiceBackendAccess:
    async def test_backend_property(self, service: SearchService):
        assert isinstance(service.backend, MemoryBackend)

    async def test_create_and_delete_index(self, service: SearchService):
        await service.create_index(IndexConfig(name="temp"))
        await service.delete_index("temp")
        # no error means success
