"""Auto-discovery registry for all SDK workflows."""

from __future__ import annotations

import importlib
import pkgutil
from typing import Any, Dict, List, Optional, Type

from databridge_core.sdk.workflows.base import BaseWorkflow

# All workflow packages to scan for auto-discovery
_WORKFLOW_PACKAGES = [
    "databridge_core.sdk.workflows.data_cleaning",
    "databridge_core.sdk.workflows.reconciliation",
    "databridge_core.sdk.workflows.hierarchy_reporting",
    "databridge_core.sdk.workflows.detection",
    "databridge_core.sdk.workflows.blce",
    "databridge_core.sdk.workflows.triage",
    "databridge_core.sdk.workflows.quality_governance",
    "databridge_core.sdk.workflows.fix_generation",
    "databridge_core.sdk.workflows.knowledge_base",
    "databridge_core.sdk.workflows.mna",
    "databridge_core.sdk.workflows.forensics",
    "databridge_core.sdk.workflows.architect",
    "databridge_core.sdk.workflows.training",
    "databridge_core.sdk.workflows.invoice_graph",
]


class WorkflowRegistry:
    """Registry that discovers and indexes all workflow classes.

    Workflows are discovered by scanning the ``sdk.workflows.*``
    sub-packages for concrete ``BaseWorkflow`` subclasses.

    Usage::

        registry = WorkflowRegistry()
        registry.discover()
        wf = registry.get("reconciliation.hash_compare")
        categories = registry.list_categories()
    """

    def __init__(self) -> None:
        self._workflows: Dict[str, Type[BaseWorkflow]] = {}
        self._discovered = False

    def discover(self) -> None:
        """Scan all workflow packages and register concrete workflows."""
        for pkg_name in _WORKFLOW_PACKAGES:
            try:
                pkg = importlib.import_module(pkg_name)
            except ImportError:
                continue

            if not hasattr(pkg, "__path__"):
                continue

            for _importer, mod_name, _is_pkg in pkgutil.iter_modules(
                pkg.__path__, prefix=pkg_name + "."
            ):
                try:
                    mod = importlib.import_module(mod_name)
                except ImportError:
                    continue

                for attr_name in dir(mod):
                    attr = getattr(mod, attr_name)
                    if (
                        isinstance(attr, type)
                        and issubclass(attr, BaseWorkflow)
                        and attr is not BaseWorkflow
                        and getattr(attr, "name", "")
                    ):
                        self._workflows[attr.name] = attr

        self._discovered = True

    def get(self, name: str) -> Optional[Type[BaseWorkflow]]:
        """Get a workflow class by dotted name."""
        if not self._discovered:
            self.discover()
        return self._workflows.get(name)

    def list_all(self) -> List[Dict[str, str]]:
        """List all registered workflows with their metadata."""
        if not self._discovered:
            self.discover()
        return [
            {
                "name": wf.name,
                "category": wf.category,
                "description": wf.description,
            }
            for wf in self._workflows.values()
        ]

    def list_categories(self) -> List[Dict[str, Any]]:
        """List workflow categories with workflow counts."""
        if not self._discovered:
            self.discover()
        categories: Dict[str, List[str]] = {}
        for wf in self._workflows.values():
            categories.setdefault(wf.category, []).append(wf.name)
        return [
            {"category": cat, "workflows": names, "count": len(names)}
            for cat, names in sorted(categories.items())
        ]

    def search(self, query: str) -> List[Dict[str, str]]:
        """Search workflows by name or description."""
        if not self._discovered:
            self.discover()
        query_lower = query.lower()
        return [
            {
                "name": wf.name,
                "category": wf.category,
                "description": wf.description,
            }
            for wf in self._workflows.values()
            if query_lower in wf.name.lower()
            or query_lower in wf.description.lower()
        ]

    @property
    def count(self) -> int:
        if not self._discovered:
            self.discover()
        return len(self._workflows)
