"""Tests for search configuration and global state management."""

from __future__ import annotations

import pytest

from search.backends.memory import MemoryBackend
from search.config import (
    BackendType,
    SearchConfig,
    close_search,
    get_search,
    init_search,
    set_search,
)


class TestSearchConfig:
    def test_default_config(self):
        cfg = SearchConfig()
        assert cfg.backend == BackendType.MEMORY
        assert "localhost" in cfg.postgres_dsn
        assert "localhost" in cfg.meilisearch_url

    def test_postgres_config(self):
        cfg = SearchConfig(
            backend=BackendType.POSTGRES,
            postgres_dsn="postgresql://user:pass@db:5432/search",
            postgres_pool_min=5,
            postgres_pool_max=20,
        )
        assert cfg.backend == BackendType.POSTGRES
        assert cfg.postgres_pool_min == 5

    def test_meilisearch_config(self):
        cfg = SearchConfig(
            backend=BackendType.MEILISEARCH,
            meilisearch_url="http://meili:7700",
            meilisearch_api_key="secret",
        )
        assert cfg.backend == BackendType.MEILISEARCH
        assert cfg.meilisearch_api_key == "secret"

    def test_pool_min_validation(self):
        with pytest.raises(Exception):
            SearchConfig(postgres_pool_min=0)


class TestGlobalState:
    async def test_init_memory_backend(self):
        backend = await init_search(SearchConfig(backend=BackendType.MEMORY))
        assert isinstance(backend, MemoryBackend)
        assert get_search() is backend

    async def test_get_search_before_init_raises(self):
        with pytest.raises(RuntimeError, match="not initialized"):
            get_search()

    async def test_set_search_overrides(self):
        custom = MemoryBackend()
        set_search(custom)
        assert get_search() is custom

    async def test_close_search(self):
        await init_search()
        await close_search()
        with pytest.raises(RuntimeError):
            get_search()

    async def test_close_when_not_initialized(self):
        await close_search()  # should not raise

    async def test_init_postgres_without_asyncpg(self):
        """Attempting postgres backend without asyncpg installed should give a clear error."""
        # This test depends on asyncpg being absent; skip if it's actually installed.
        try:
            import asyncpg  # noqa: F401

            pytest.skip("asyncpg is installed, cannot test import error")
        except ImportError:
            pass

        with pytest.raises(ImportError, match="willian-search\\[postgres\\]"):
            await init_search(SearchConfig(backend=BackendType.POSTGRES))

    async def test_init_meilisearch_without_sdk(self):
        """Attempting meilisearch backend without SDK should give a clear error."""
        try:
            import meilisearch_python_sdk  # noqa: F401

            pytest.skip("meilisearch-python-sdk is installed, cannot test import error")
        except ImportError:
            pass

        with pytest.raises(ImportError, match="willian-search\\[meilisearch\\]"):
            await init_search(SearchConfig(backend=BackendType.MEILISEARCH))
