from __future__ import annotations
import sys
from importlib.machinery import ModuleSpec, PathFinder
from importlib.machinery import all_suffixes as module_suffixes
from importlib.util import spec_from_file_location
from itertools import chain
from pathlib import Path

MAPPING: dict[str, str] = {'acp_adapter': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\acp_adapter', 'agent': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\agent', 'batch_runner': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\batch_runner', 'cli': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\cli', 'cron': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\cron', 'gateway': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\gateway', 'hermes_bootstrap': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\hermes_bootstrap', 'hermes_cli': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\hermes_cli', 'hermes_constants': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\hermes_constants', 'hermes_logging': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\hermes_logging', 'hermes_state': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\hermes_state', 'hermes_time': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\hermes_time', 'mcp_serve': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\mcp_serve', 'model_tools': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\model_tools', 'plugins': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins', 'providers': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\providers', 'run_agent': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\run_agent', 'tools': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\tools', 'toolset_distributions': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\toolset_distributions', 'toolsets': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\toolsets', 'trajectory_compressor': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\trajectory_compressor', 'tui_gateway': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\tui_gateway', 'utils': 'C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\utils'}
NAMESPACES: dict[str, list[str]] = {'gateway.assets': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\gateway\\assets'], 'plugins.browser': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\browser'], 'plugins.dashboard_auth': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\dashboard_auth'], 'plugins.hermes-achievements': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\hermes-achievements'], 'plugins.image_gen': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\image_gen'], 'plugins.kanban': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\kanban'], 'plugins.model-providers': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\model-providers'], 'plugins.observability': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\observability'], 'plugins.platforms': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\platforms'], 'plugins.video_gen': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\video_gen'], 'plugins.hermes-achievements.dashboard': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\hermes-achievements\\dashboard'], 'plugins.hermes-achievements.docs': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\hermes-achievements\\docs'], 'plugins.hermes-achievements.tests': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\hermes-achievements\\tests'], 'plugins.hermes-achievements.dashboard.dist': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\hermes-achievements\\dashboard\\dist'], 'plugins.hermes-achievements.docs.assets': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\hermes-achievements\\docs\\assets'], 'plugins.kanban.dashboard': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\kanban\\dashboard'], 'plugins.kanban.systemd': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\kanban\\systemd'], 'plugins.kanban.dashboard.dist': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\kanban\\dashboard\\dist'], 'plugins.platforms.photon.sidecar': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\plugins\\platforms\\photon\\sidecar'], 'tools.neutts_samples': ['C:\\Users\\server\\AppData\\Local\\hermes\\hermes-agent\\tools\\neutts_samples']}
PATH_PLACEHOLDER = '__editable__.hermes_agent-0.18.2.finder' + ".__path_hook__"


class _EditableFinder:  # MetaPathFinder
    @classmethod
    def find_spec(cls, fullname: str, path=None, target=None) -> ModuleSpec | None:  # type: ignore
        # Top-level packages and modules (we know these exist in the FS)
        if fullname in MAPPING:
            pkg_path = MAPPING[fullname]
            return cls._find_spec(fullname, Path(pkg_path))

        # Handle immediate children modules (required for namespaces to work)
        # To avoid problems with case sensitivity in the file system we delegate
        # to the importlib.machinery implementation.
        parent, _, child = fullname.rpartition(".")
        if parent and parent in MAPPING:
            return PathFinder.find_spec(fullname, path=[MAPPING[parent]])

        # Other levels of nesting should be handled automatically by importlib
        # using the parent path.
        return None

    @classmethod
    def _find_spec(cls, fullname: str, candidate_path: Path) -> ModuleSpec | None:
        init = candidate_path / "__init__.py"
        candidates = (candidate_path.with_suffix(x) for x in module_suffixes())
        for candidate in chain([init], candidates):
            if candidate.exists():
                return spec_from_file_location(fullname, candidate)
        return None


class _EditableNamespaceFinder:  # PathEntryFinder
    @classmethod
    def _path_hook(cls, path) -> type[_EditableNamespaceFinder]:
        if path == PATH_PLACEHOLDER:
            return cls
        raise ImportError

    @classmethod
    def _paths(cls, fullname: str) -> list[str]:
        paths = NAMESPACES[fullname]
        if not paths and fullname in MAPPING:
            paths = [MAPPING[fullname]]
        # Always add placeholder, for 2 reasons:
        # 1. __path__ cannot be empty for the spec to be considered namespace.
        # 2. In the case of nested namespaces, we need to force
        #    import machinery to query _EditableNamespaceFinder again.
        return [*paths, PATH_PLACEHOLDER]

    @classmethod
    def find_spec(cls, fullname: str, target=None) -> ModuleSpec | None:  # type: ignore
        if fullname in NAMESPACES:
            spec = ModuleSpec(fullname, None, is_package=True)
            spec.submodule_search_locations = cls._paths(fullname)
            return spec
        return None

    @classmethod
    def find_module(cls, _fullname) -> None:
        return None


def install():
    if not any(finder == _EditableFinder for finder in sys.meta_path):
        sys.meta_path.append(_EditableFinder)

    if not NAMESPACES:
        return

    if not any(hook == _EditableNamespaceFinder._path_hook for hook in sys.path_hooks):
        # PathEntryFinder is needed to create NamespaceSpec without private APIS
        sys.path_hooks.append(_EditableNamespaceFinder._path_hook)
    if PATH_PLACEHOLDER not in sys.path:
        sys.path.append(PATH_PLACEHOLDER)  # Used just to trigger the path hook
