"""
Central module for registering and retrieving decoupled plugin resources.

This module provides the `BaseRegistry` and its specialized subclasses for
registering Views, Schemas, UI Components, Tools, Generators, and Environments
across independent Django apps without hard dependencies.
"""


class BaseRegistry:
    """
    Base registry class. Provides a generic dictionary-based registration pattern.
    Should be subclassed for each specific resource type (e.g., UI, View, Generator).
    """

    _registry = {}
    _type_name: str = "item"

    @classmethod
    def register(cls, key: str):
        """
        Decorator to register a class under a specific string key.

        Args:
            key (str): The unique string identifier for the registered item.
                       Conventionally formatted as `app_name.ClassName`.

        Returns:
            callable: The decorator function wrapping the targeted class.
        """

        def decorator(klass):
            cls._registry[key] = klass
            return klass

        return decorator

    @classmethod
    def get(cls, key: str):
        """
        Retrieve a registered class by its string key.

        Args:
            key (str): The unique identifier.

        Returns:
            type: The registered class.

        Raises:
            ValueError: If no item is registered under the provided key.
        """
        rVal = cls._registry.get(key)
        if not rVal:
            raise ValueError(f"Component {key} not found")
        return rVal

    @classmethod
    def all(cls):
        """Return all registered items."""
        return dict(cls._registry)

    @classmethod
    def keys(cls):
        """Return all registered keys."""
        return list(cls._registry.keys())


class ViewRegistry(BaseRegistry):
    """Registry for Django View classes."""

    _registry = {}
    _type_name = "view"


class SchemaRegistry(BaseRegistry):
    """Registry for Pydantic or Django REST Framework schemas."""

    _registry = {}
    _type_name = "schema"


class UIRegistry(BaseRegistry):
    """Registry for python-based UI Components."""

    _registry = {}
    _type_name = "ui"


class ToolRegistry(BaseRegistry):
    """Registry for LangChain or MCP tools exposed by plugins."""

    _registry = {}
    _type_name = "tool"


class GeneratorRegistry(BaseRegistry):
    """
    Registry for data generators used to seed databases.
    Implements topological sorting to ensure generators run in the correct
    dependency order.
    """

    _registry = {}
    _type_name = "generator"

    @classmethod
    def run_all(cls):
        """
        Run all registered data generators in their declared dependency order.
        Each generator must implement a `.run()` method.
        """
        ordered = cls._resolve_order()
        for key in ordered:
            generator_cls = cls._registry[key]
            print(f"\n=== Running {key} ===")
            generator_cls().run()

    @classmethod
    def _resolve_order(cls) -> list[str]:
        """
        Perform a topological sort based on generator dependencies.

        Returns:
            list[str]: A list of generator keys ordered by dependency resolution.
        """
        from collections import deque

        in_degree = {k: 0 for k in cls._registry}
        graph = {k: [] for k in cls._registry}

        for key, gen_cls in cls._registry.items():
            for dep in getattr(gen_cls, "dependencies", []):
                if dep in cls._registry:
                    graph[dep].append(key)
                    in_degree[key] += 1

        queue = deque([k for k, d in in_degree.items() if d == 0])
        result = []

        while queue:
            node = queue.popleft()
            result.append(node)
            for neighbor in graph[node]:
                in_degree[neighbor] -= 1
                if in_degree[neighbor] == 0:
                    queue.append(neighbor)

        return result


class EnvironmentRegistry(BaseRegistry):
    """Registry for application-specific environment/context handlers."""

    _registry = {}
    _type_name = "environment"

    @classmethod
    def get_for_app(cls, app_name):
        """Get environment class for a specific app."""
        return cls.get(app_name)


class ConfigRegistry(BaseRegistry):
    """Registry for Django AppConfig classes."""

    _registry = {}
    _type_name = "config"
