"""Base backend interface for mykb."""

from abc import ABC, abstractmethod
from dataclasses import dataclass


@dataclass
class SearchHit:
    """Unified search result item."""

    id: str
    score: float
    document: dict  # raw document fields


@dataclass
class SearchResult:
    """Search response."""

    hits: list[SearchHit]
    processing_time_ms: int
    total_hits: int | None = None


class BaseBackend(ABC):
    """Abstract base class for database backends."""

    @abstractmethod
    def initialize(self, collection: str, dimension: int) -> None:
        """
        Initialize collection/index.
        Creates if not exists, validates schema compatibility if exists.
        """
        ...

    @abstractmethod
    def add_documents(self, collection: str, documents: list[dict]) -> int:
        """
        Add or update documents.
        documents format: [{"id": "...", "content": "...", "title": "...", ...}]
        Returns number of successfully added documents.
        """
        ...

    @abstractmethod
    def delete_documents(self, collection: str, ids: list[str]) -> int:
        """
        Delete documents by ID.
        Returns number of successfully deleted documents.
        """
        ...

    @abstractmethod
    def update_embeddings(self, collection: str, id_vectors: dict[str, list[float]]) -> int:
        """
        Update document embeddings.
        id_vectors: {"doc_id": [0.1, 0.2, ...], ...}
        Returns number of successfully updated documents.
        """
        ...

    @abstractmethod
    def bm25_search(
        self,
        collection: str,
        query: str,
        limit: int = 10,
        filter: dict | None = None,
    ) -> SearchResult:
        """Pure BM25 full-text search."""
        ...

    @abstractmethod
    def vector_search(
        self,
        collection: str,
        vector: list[float],
        limit: int = 10,
        filter: dict | None = None,
    ) -> SearchResult:
        """Pure vector search."""
        ...

    @abstractmethod
    def hybrid_search(
        self,
        collection: str,
        query: str,
        vector: list[float],
        limit: int = 10,
        semantic_ratio: float = 0.5,
        filter: dict | None = None,
    ) -> SearchResult:
        """
        Hybrid search combining BM25 and vector.
        semantic_ratio: 0.0 = pure BM25, 1.0 = pure vector
        """
        ...

    @abstractmethod
    def get_document(self, collection: str, id: str) -> dict | None:
        """Get a single document by ID."""
        ...

    @abstractmethod
    def get_documents(
        self,
        collection: str,
        limit: int = 1000,
        offset: int = 0,
        filter: str | None = None,
    ) -> list[dict]:
        """
        Get documents with pagination.
        Returns list of document dicts.
        """
        ...

    @abstractmethod
    def get_stats(self, collection: str) -> dict:
        """
        Get collection statistics.
        Returns: {"total_documents": int, "indexed_documents": int, ...}
        """
        ...

    @abstractmethod
    def health_check(self) -> dict:
        """
        Health check.
        Returns: {"status": "ok"|"error", "message": "...", ...}
        """
        ...

    def close(self) -> None:
        """Close connection (optional implementation)."""
        pass
