"""VDB backend registry and factory helpers.

Concrete VDB adapters (e.g. in ``isage-vdb``) register themselves with
:func:`register_backend` so that consumers can instantiate them by name
via :func:`create_backend` without importing the concrete package directly.

Example (in ``isage-vdb``)::

    from sage.libs.vdb import VDBBackend, register_backend

    @register_backend("sagedb")
    class SageDBAdapter(VDBBackend):
        def __init__(self, config: dict):
            ...

Example (consumer)::

    from sage.libs.vdb import create_backend

    backend = create_backend("sagedb", {"db_path": "./data", "dim": 768})
"""

from __future__ import annotations

from typing import Any

from sage.libs.vdb.interface import VDBBackend

_registry: dict[str, type[VDBBackend]] = {}


class VDBRegistryError(Exception):
    """Raised when a backend is not found or registration fails."""


def register_backend(name: str):
    """Class decorator that registers a :class:`VDBBackend` implementation.

    Args:
        name: Short identifier for this backend (e.g. ``"sagedb"``).

    Returns:
        The original class, unchanged.

    Raises:
        VDBRegistryError: If a backend with the same name was already
            registered.
    """

    def decorator(cls: type[VDBBackend]) -> type[VDBBackend]:
        if name in _registry:
            raise VDBRegistryError(
                f"VDB backend '{name}' is already registered (registered as {_registry[name]!r})."
            )
        if not issubclass(cls, VDBBackend):
            raise VDBRegistryError(f"Class {cls!r} must subclass VDBBackend to be registered.")
        _registry[name] = cls
        return cls

    return decorator


def create_backend(name: str, config: dict[str, Any] | None = None) -> VDBBackend:
    """Instantiate a registered VDB backend by name.

    All registered backends must accept a single ``config: dict`` positional
    argument in their constructor (following the convention
    ``MyBackend(config: dict)``).

    Args:
        name: Backend identifier previously registered via
            :func:`register_backend`.
        config: Optional configuration dict passed as the first positional
            argument to the backend constructor.

    Returns:
        A concrete :class:`VDBBackend` instance.

    Raises:
        VDBRegistryError: If no backend with ``name`` has been registered.
    """
    if name not in _registry:
        available = list(_registry.keys())
        raise VDBRegistryError(
            f"VDB backend '{name}' is not registered. "
            f"Available backends: {available}. "
            f"Install the appropriate package (e.g. 'pip install isage-vdb') "
            f"and ensure it registers itself on import."
        )
    return _registry[name](config or {})


def list_backends() -> list[str]:
    """Return the names of all currently registered VDB backends."""
    return list(_registry.keys())
