"""Meta path finder for Mira archives."""

from __future__ import annotations

import importlib.abc
import importlib.machinery

from mira.runtime.loader import MiraLoader, NATIVE_EXTENSIONS
from mira.runtime.registry import MiraRegistry, MiraPackageInfo


class MiraFinder(importlib.abc.MetaPathFinder):
    """Find modules inside loaded .mira packages."""

    def __init__(self, registry: MiraRegistry | None = None) -> None:
        """Create a finder bound to a registry."""
        self.registry = registry or MiraRegistry()

    def find_spec(self, fullname: str, path=None, target=None):  # type: ignore[override]
        """Return a ModuleSpec for modules found inside loaded .mira archives."""
        for package in self.registry.list_all():
            result = self._find_in_package(package, fullname)
            if result is None:
                continue
            path_in_zip, is_package, file_type = result
            loader = MiraLoader(package, path_in_zip, file_type, is_package)
            origin = f"mira://{package.name}/{path_in_zip}"
            spec = importlib.machinery.ModuleSpec(
                fullname,
                loader,
                origin=origin,
                is_package=is_package,
            )
            if is_package:
                spec.submodule_search_locations = [origin]
            return spec
        return None

    def find_module(self, fullname: str, path=None):  # type: ignore[override]
        """Legacy finder interface for Python versions that call find_module."""
        spec = self.find_spec(fullname, path)
        return spec.loader if spec else None

    def _find_in_package(
        self, package: MiraPackageInfo, fullname: str
    ) -> tuple[str, bool, str] | None:
        """Find a module inside a specific .mira package."""
        module_path = fullname.replace(".", "/")
        candidates: list[str] = []

        if fullname == package.include:
            candidates.append(f"{package.include}/__init__.pyc")
        elif fullname.startswith(package.include + "."):
            rel_module = fullname[len(package.include) + 1 :].replace(".", "/")
            candidates.extend(
                [
                    f"{package.include}/{rel_module}.pyc",
                    f"{package.include}/{rel_module}/__init__.pyc",
                ]
            )

        candidates.extend(
            [
                f"libs/{module_path}.pyc",
                f"libs/{module_path}/__init__.pyc",
            ]
        )

        for path in candidates:
            if path in package.files:
                is_package = path.endswith("/__init__.pyc")
                return path, is_package, "pyc"

        for ext in NATIVE_EXTENSIONS:
            native_candidates = [
                f"dlls/{module_path}{ext}",
                f"dlls/{module_path}/__init__{ext}",
            ]
            for path in native_candidates:
                if path in package.files:
                    is_package = path.endswith(f"/__init__{ext}")
                    return path, is_package, "native"

        return None
