# packages/leann-core/src/leann/registry.py

import importlib
import importlib.metadata
import json
import logging
from pathlib import Path
from typing import TYPE_CHECKING, Optional, Union

if TYPE_CHECKING:
    from leann.interface import LeannBackendFactoryInterface

# Set up logger for this module
logger = logging.getLogger(__name__)

BACKEND_REGISTRY: dict[str, "LeannBackendFactoryInterface"] = {}


def register_backend(name: str):
    """A decorator to register a new backend class."""

    def decorator(cls):
        logger.debug(f"Registering backend '{name}'")
        BACKEND_REGISTRY[name] = cls
        return cls

    return decorator


def autodiscover_backends():
    """Automatically discovers and imports all 'leann-backend-*' packages."""
    # print("INFO: Starting backend auto-discovery...")
    discovered_backends = []
    for dist in importlib.metadata.distributions():
        dist_name = dist.metadata["name"]
        if dist_name.startswith("leann-backend-"):
            backend_module_name = dist_name.replace("-", "_")
            discovered_backends.append(backend_module_name)

    for backend_module_name in sorted(discovered_backends):  # sort for deterministic loading
        try:
            importlib.import_module(backend_module_name)
            # Registration message is printed by the decorator
        except ImportError:
            # print(f"WARN: Could not import backend module '{backend_module_name}': {e}")
            pass
    # print("INFO: Backend auto-discovery finished.")


def register_project_directory(project_dir: Optional[Union[str, Path]] = None):
    """
    Register a project directory in the global LEANN registry.

    This allows `leann list` to discover indexes created by apps or other tools.

    Args:
        project_dir: Directory to register. If None, uses current working directory.
    """
    if project_dir is None:
        project_dir = Path.cwd()
    else:
        project_dir = Path(project_dir)

    # Only register directories that have some kind of LEANN content
    # Either .leann/indexes/ (CLI format) or *.leann.meta.json files (apps format)
    has_cli_indexes = (project_dir / ".leann" / "indexes").exists()
    has_app_indexes = any(project_dir.rglob("*.leann.meta.json"))

    if not (has_cli_indexes or has_app_indexes):
        # Don't register if there are no LEANN indexes
        return

    global_registry = Path.home() / ".leann" / "projects.json"
    global_registry.parent.mkdir(exist_ok=True)

    project_str = str(project_dir.resolve())

    # Load existing registry
    projects = []
    if global_registry.exists():
        try:
            with open(global_registry) as f:
                projects = json.load(f)
        except Exception:
            logger.debug("Could not load existing project registry")
            projects = []

    # Add project if not already present
    if project_str not in projects:
        projects.append(project_str)

        # Save updated registry
        try:
            with open(global_registry, "w") as f:
                json.dump(projects, f, indent=2)
            logger.debug(f"Registered project directory: {project_str}")
        except Exception as e:
            logger.warning(f"Could not save project registry: {e}")
