# compiler/loader.py
from __future__ import annotations

import importlib
import logging
import pkgutil
from types import ModuleType

logger = logging.getLogger(__name__)

_DEFAULT_BASES = ["steeleagle_sdk.dsl.types"]
_SKIP_RULES = [
    lambda short: short.startswith("_"),
    lambda short: short == "native",
]


def _walk_package(base: str) -> tuple[ModuleType | None, list[str]]:
    try:
        pkg: ModuleType = importlib.import_module(base)
    except ModuleNotFoundError:
        return None, []
    modules: list[str] = []
    for m in pkgutil.walk_packages(pkg.__path__, pkg.__name__ + "."):
        mod_name = m.name.rsplit(".", 1)[-1]
        if any(rule(mod_name) for rule in _SKIP_RULES):
            logger.debug("   -> skipping %s (ignored)", m.name)
            continue
        modules.append(m.name)
    return pkg, modules


def load_all(
    *base_pkgs: str,
) -> list[dict[str, object]]:
    """
    Import every submodule under each base package and REPORT failures.
    """
    if not base_pkgs:
        base_pkgs = _DEFAULT_BASES
    all_summaries: list[dict[str, object]] = []

    for base in base_pkgs:
        # init summary
        summary: dict[str, object] = {
            "base": base,
            "imported": [],
            "failed": [],
            "skipped": False,
            "missing_base": False,
        }

        # walk package
        pkg, modules = _walk_package(base)
        if pkg is None:
            summary["missing_base"] = True
            logger.warning("Base package not found: %s", base)
            all_summaries.append(summary)
            continue
        logger.debug("Scanning '%s' (%d submodules discovered)", base, len(modules))

        # import submodules
        imported: list[str] = []
        failed: list[dict[str, str]] = []
        for module in modules:
            try:
                logger.debug(" importing %s ...", module)
                importlib.import_module(module)
                imported.append(module)
                logger.debug("   -> OK")
            except Exception as e:
                fail_rec = {
                    "module": module,
                    "exc_type": type(e).__name__,
                    "message": str(e),
                }
                failed.append(fail_rec)
                logger.error(
                    "   -> FAIL importing %s: %s: %s", module, type(e).__name__, e
                )
        summary["imported"] = imported
        summary["failed"] = failed
        all_summaries.append(summary)
    return all_summaries


def print_report(summaries: list[dict[str, object]]) -> None:
    """Pretty-print the summaries returned by load_all()."""
    for s in summaries:
        base = s["base"]
        if s.get("skipped"):
            logger.debug("%s: skipped (already scanned)", base)
            continue
        if s.get("missing_base"):
            logger.warning("%s: MISSING base package", base)
            continue

        imported = s.get("imported", [])
        failed = s.get("failed", [])
        logger.debug("%s: %d imported, %d failed", base, len(imported), len(failed))

        if imported:
            for name in imported[:10]:
                logger.debug("   ✓ %s", name)
            if len(imported) > 10:
                logger.debug("   … (+%d more)", len(imported) - 10)

        if failed:
            for f in failed:
                logger.error(
                    "   ✗ %s — %s: %s", f["module"], f["exc_type"], f["message"]
                )
