"""Fail-closed resolver for modules loaded from one configured DualCoach profile."""

from __future__ import annotations

import importlib
import sys
from collections.abc import Callable
from dataclasses import dataclass
from pathlib import Path
from types import ModuleType


@dataclass(frozen=True, slots=True)
class ProfilePackageResolutionError(RuntimeError):
    detail: str

    def __str__(self) -> str:
        return self.detail


@dataclass(frozen=True, slots=True)
class DualCoachProfilePackage:
    """Resolve modules only when their source belongs to the configured package."""

    root: Path
    package: Path

    @classmethod
    def from_root(cls, root: Path | str) -> DualCoachProfilePackage:
        configured = Path(root)
        if not configured.is_absolute():
            raise ProfilePackageResolutionError(
                "configured profile package must be absolute"
            )
        if configured.is_symlink():
            raise ProfilePackageResolutionError(
                "configured profile package must not be a symlink"
            )
        resolved = configured.resolve()
        package = resolved / "checkin_cli"
        if (
            not resolved.is_dir()
            or package.is_symlink()
            or not package.is_dir()
            or not (package / "__init__.py").is_file()
        ):
            raise ProfilePackageResolutionError(
                "configured profile package is unavailable"
            )
        return cls(root=resolved, package=package.resolve())

    def resolve(
        self,
        module_name: str,
        *,
        importer: Callable[[str], ModuleType] = importlib.import_module,
    ) -> ModuleType:
        expected_prefix = "checkin_cli."
        if not module_name.startswith(expected_prefix):
            raise ProfilePackageResolutionError(
                "profile module name is outside checkin_cli"
            )
        root_text = str(self.root)
        if root_text not in sys.path:
            sys.path.insert(0, root_text)
        module = importer(module_name)
        source_value = getattr(module, "__file__", None)
        if not isinstance(source_value, str):
            raise ProfilePackageResolutionError(
                "profile module source is unavailable"
            )
        source = Path(source_value)
        if source.is_symlink() or not source.resolve().is_relative_to(self.package):
            raise ProfilePackageResolutionError(
                "profile module is outside configured profile"
            )
        return module


__all__ = [
    "DualCoachProfilePackage",
    "ProfilePackageResolutionError",
]
