"""Tests for the Search API endpoints."""

import pytest
from httpx import AsyncClient


@pytest.mark.asyncio
class TestSearchEndpoint:
    """POST /api/v1/search — hybrid search."""

    async def test_search_requires_auth(self, client: AsyncClient, api_prefix: str):
        """Search should reject unauthenticated requests."""
        resp = await client.post(f"{api_prefix}/search", json={
            "query": "数字政府",
        })
        assert resp.status_code in (401, 403)

    async def test_search_basic(self, client: AsyncClient, api_prefix: str, auth_headers: dict):
        """Search with a simple keyword should return 200."""
        resp = await client.post(
            f"{api_prefix}/search",
            json={"query": "数字政府"},
            headers=auth_headers,
        )
        assert resp.status_code == 200
        body = resp.json()
        assert "total" in body
        assert "documents" in body
        assert "page" in body
        assert "page_size" in body
        assert isinstance(body["documents"], list)

    async def test_search_with_filters(self, client: AsyncClient, api_prefix: str, auth_headers: dict):
        """Search with facet filters should work."""
        resp = await client.post(
            f"{api_prefix}/search",
            json={
                "query": "政务服务",
                "filters": {
                    "doc_type": "通知",
                },
                "page": 1,
                "page_size": 10,
            },
            headers=auth_headers,
        )
        assert resp.status_code == 200
        body = resp.json()
        assert body["page"] == 1
        assert body["page_size"] == 10

    async def test_search_with_extended_filters_and_scope(self, client: AsyncClient, api_prefix: str, auth_headers: dict):
        """Search should accept knowledge category, doc number, and scope filters."""
        resp = await client.post(
            f"{api_prefix}/search",
            json={
                "query": "国办发",
                "filters": {
                    "knowledge_category": "政策文件",
                    "doc_number": "〔2024〕",
                    "search_scope": "doc_number",
                },
                "page": 1,
                "page_size": 10,
            },
            headers=auth_headers,
        )
        assert resp.status_code == 200
        body = resp.json()
        assert body["page"] == 1
        assert body["page_size"] == 10

    async def test_search_with_scene_signer_and_year_filters(self, client: AsyncClient, api_prefix: str, auth_headers: dict):
        """Search should accept document scene type, signer, and publish year filters."""
        resp = await client.post(
            f"{api_prefix}/search",
            json={
                "query": "办事指南",
                "filters": {
                    "document_scene_type": "standard_service_guide",
                    "signer": "张三",
                    "publish_year": 2024,
                },
                "page": 1,
                "page_size": 10,
            },
            headers=auth_headers,
        )
        assert resp.status_code == 200
        body = resp.json()
        assert body["page"] == 1
        assert body["page_size"] == 10

    async def test_search_pagination(self, client: AsyncClient, api_prefix: str, auth_headers: dict):
        """Pagination parameters should be respected."""
        resp = await client.post(
            f"{api_prefix}/search",
            json={"query": "改革", "page": 2, "page_size": 5},
            headers=auth_headers,
        )
        assert resp.status_code == 200
        body = resp.json()
        assert body["page"] == 2
        assert body["page_size"] == 5

    async def test_search_empty_query_rejected(self, client: AsyncClient, api_prefix: str, auth_headers: dict):
        """Empty query string should be rejected (422)."""
        resp = await client.post(
            f"{api_prefix}/search",
            json={"query": ""},
            headers=auth_headers,
        )
        assert resp.status_code == 422

    async def test_search_aggregations(self, client: AsyncClient, api_prefix: str, auth_headers: dict):
        """Search response should include aggregation facets."""
        resp = await client.post(
            f"{api_prefix}/search",
            json={"query": "规划"},
            headers=auth_headers,
        )
        assert resp.status_code == 200
        body = resp.json()
        assert "aggregations" in body


@pytest.mark.asyncio
class TestSuggestEndpoint:
    """POST /api/v1/search/suggest — query suggestions."""

    async def test_suggest_requires_auth(self, client: AsyncClient, api_prefix: str):
        resp = await client.post(f"{api_prefix}/search/suggest", json={
            "query": "数字",
        })
        assert resp.status_code in (401, 403)

    async def test_suggest_basic(self, client: AsyncClient, api_prefix: str, auth_headers: dict):
        resp = await client.post(
            f"{api_prefix}/search/suggest",
            json={"query": "数字", "size": 5},
            headers=auth_headers,
        )
        assert resp.status_code == 200
        body = resp.json()
        assert "suggestions" in body
        assert isinstance(body["suggestions"], list)


@pytest.mark.asyncio
class TestFilterOptionsEndpoint:
    """GET /api/v1/search/filter-options — search filter options."""

    async def test_filter_options_requires_auth(self, client: AsyncClient, api_prefix: str):
        resp = await client.get(f"{api_prefix}/search/filter-options")
        assert resp.status_code in (401, 403)

    async def test_filter_options_include_subject_words(self, client: AsyncClient, api_prefix: str, auth_headers: dict):
        resp = await client.get(
            f"{api_prefix}/search/filter-options",
            headers=auth_headers,
        )
        assert resp.status_code == 200
        body = resp.json()
        assert "knowledge_categories" in body
        assert "doc_types" in body
        assert "document_scene_types" in body
        assert "subject_words" in body
        assert isinstance(body["subject_words"], list)
