"""Search configuration and global instance management."""

from __future__ import annotations

from enum import Enum
from typing import Any

from pydantic import BaseModel, Field

from search.backends.base import SearchBackend


class BackendType(str, Enum):
    MEMORY = "memory"
    POSTGRES = "postgres"
    MEILISEARCH = "meilisearch"


class SearchConfig(BaseModel):
    """Configuration for the search system.

    Attributes:
        backend: Which backend to use.
        postgres_dsn: PostgreSQL connection string (only for ``postgres`` backend).
        postgres_pool_min: Minimum pool connections.
        postgres_pool_max: Maximum pool connections.
        meilisearch_url: Meilisearch server URL (only for ``meilisearch`` backend).
        meilisearch_api_key: Meilisearch API key.
    """

    backend: BackendType = BackendType.MEMORY
    postgres_dsn: str = "postgresql://localhost:5432/search"
    postgres_pool_min: int = Field(default=2, ge=1)
    postgres_pool_max: int = Field(default=10, ge=1)
    meilisearch_url: str = "http://localhost:7700"
    meilisearch_api_key: str | None = None


# -- global state --------------------------------------------------------------

_backend: SearchBackend | None = None


async def init_search(config: SearchConfig | None = None) -> SearchBackend:
    """Initialize the global search backend from config.

    Returns the created backend instance.
    """
    global _backend
    cfg = config or SearchConfig()

    if cfg.backend == BackendType.POSTGRES:
        try:
            import asyncpg
        except ImportError as exc:
            raise ImportError(
                "Install willian-search[postgres] to use the PostgreSQL backend."
            ) from exc

        pool = await asyncpg.create_pool(
            cfg.postgres_dsn,
            min_size=cfg.postgres_pool_min,
            max_size=cfg.postgres_pool_max,
        )
        from search.backends.postgres import PostgresBackend

        _backend = PostgresBackend(pool=pool)

    elif cfg.backend == BackendType.MEILISEARCH:
        try:
            from meilisearch_python_sdk import AsyncClient
        except ImportError as exc:
            raise ImportError(
                "Install willian-search[meilisearch] to use the Meilisearch backend."
            ) from exc

        client = AsyncClient(cfg.meilisearch_url, cfg.meilisearch_api_key)
        from search.backends.meilisearch import MeilisearchBackend

        _backend = MeilisearchBackend(client=client)

    else:
        from search.backends.memory import MemoryBackend

        _backend = MemoryBackend()

    return _backend


def get_search() -> SearchBackend:
    """Return the active search backend. Raises if not initialized."""
    if _backend is None:
        raise RuntimeError("Search not initialized. Call init_search() first.")
    return _backend


def set_search(backend: SearchBackend) -> None:
    """Override the global search backend (useful for testing)."""
    global _backend
    _backend = backend


async def close_search() -> None:
    """Close the global search backend and release resources."""
    global _backend
    if _backend is not None:
        await _backend.close()
        _backend = None
