"""
mizan Auto-Discovery

Scans Django apps for server functions following the 'clients' layer convention:
- <app>/clients.py
- <app>/clients/**/*.py

Usage in urls.py:
    from mizan.setup.discovery import mizan_clients

    mizan_clients('apps')  # Scans apps/*/clients.py
    mizan_clients('mizan', 'allauth')  # Scans mizan/allauth/**/*.py

This replaces manual "import to register" patterns with explicit auto-discovery.
"""

from typing import Any

from mizan._vendor.app_visitor import DjangoAppVisitor, get_members

from mizan_core.registry import register, get_function
from mizan_core.client.function import ServerFunction


class _RegisterServerFunctions:
    """Visitor handler that registers ServerFunction subclasses."""

    def on_module(
        self, app_name: str, path_parts: list[str], members: list[tuple[str, Any]]
    ) -> None:
        """Process discovered module members."""
        for name, member in members:
            # Register ServerFunction subclasses
            if (
                isinstance(member, type)
                and issubclass(member, ServerFunction)
                and member is not ServerFunction
                and hasattr(member, "__name__")
            ):
                # Use the function name as registration name
                fn_name = getattr(member, "name", None) or member.__name__

                # Skip already registered (idempotent)
                if get_function(fn_name) is member:
                    continue

                try:
                    register(member, fn_name)
                except ValueError:
                    # Already registered with different class - skip
                    pass


def mizan_clients(apps_root: str, layer: str = "clients") -> None:
    """
    Discover and register server functions from Django apps.

    Scans for the specified layer (default: 'clients') in each app:
    - <app>/<layer>.py
    - <app>/<layer>/**/*.py

    Args:
        apps_root: Root package containing Django apps (e.g., 'apps')
        layer: Module name pattern to scan (default: 'clients')

    Example:
        # In urls.py
        mizan_clients('apps')  # Scans apps/*/clients.py
        mizan_clients('apps', 'functions')  # Scans apps/*/functions.py
    """
    visitor = DjangoAppVisitor(layer=layer, apps_root=apps_root)
    visitor.visit(_RegisterServerFunctions())


def mizan_module(module_path: str) -> None:
    """
    Register server functions from a specific module.

    Use this for library modules that don't follow the app convention.

    Args:
        module_path: Full module path (e.g., 'mizan.integrations.allauth')

    Example:
        mizan_module('mizan.integrations.allauth')
        mizan_module('mizan.jwt.functions')
    """
    members = get_members(module_path)
    handler = _RegisterServerFunctions()
    handler.on_module("", [], members)
