"""Abstract VDBBackend protocol.

Defines the minimal contract that any vector-database backend must satisfy so
that L4 packages (``isage-neuromem``, etc.) can depend on this stable interface
rather than a concrete implementation.
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Any


class VDBBackend(ABC):
    """Abstract vector-database backend.

    Implementations must provide the following vector-store operations.
    All methods operate on batches of items identified by string IDs.

    Concrete adapters (e.g. ``SageDBAdapter`` in ``isage-vdb``) should subclass
    this and be registered via :func:`sage.libs.vdb.register_backend`.
    """

    # ------------------------------------------------------------------
    # Write operations
    # ------------------------------------------------------------------

    @abstractmethod
    def add(
        self,
        ids: list[str],
        vectors: list[list[float]],
        metadata: list[dict[str, Any]],
    ) -> None:
        """Insert or upsert a batch of vectors.

        Args:
            ids: Unique string identifiers for each item.
            vectors: Dense float vectors; each inner list must have the same
                dimensionality as the index.
            metadata: Arbitrary JSON-serialisable metadata dicts, one per
                vector.  Must be the same length as ``ids``.

        Raises:
            ValueError: If lengths of ``ids``, ``vectors``, ``metadata`` differ.
        """

    @abstractmethod
    def delete(self, ids: list[str]) -> bool:
        """Delete items by ID.

        Args:
            ids: List of IDs to remove.

        Returns:
            ``True`` if at least one item was deleted; ``False`` otherwise.
        """

    @abstractmethod
    def clear(self) -> bool:
        """Remove all items from the backend.

        Returns:
            ``True`` on success.
        """

    # ------------------------------------------------------------------
    # Read operations
    # ------------------------------------------------------------------

    @abstractmethod
    def query(
        self,
        filter_metadata: dict[str, Any] | None = None,
        top_k: int = 10,
        query_vector: list[float] | None = None,
    ) -> list[dict[str, Any]]:
        """Retrieve items by metadata filter and/or vector similarity.

        Args:
            filter_metadata: Key/value pairs that must match an item's stored
                metadata.  Pass ``None`` to skip metadata filtering.
            top_k: Maximum number of results to return.
            query_vector: If provided, rank results by similarity to this
                vector (nearest-first).

        Returns:
            List of result dicts; each dict should contain at minimum the
            fields ``id``, ``vector``, and ``metadata``.
        """

    @abstractmethod
    def get_all_ids(self) -> list[str]:
        """Return all item IDs stored in the backend."""

    @abstractmethod
    def count(self) -> int:
        """Return the total number of items stored in the backend."""
