from __future__ import annotations

import importlib
from typing import Any

TRAZAEO_UNAVAILABLE_MESSAGE = "trazaeo Python bindings are unavailable"


def require_module(
    module_name: str,
    message: str,
    *,
    error_cls: type[Exception],
) -> Any:
    try:
        return importlib.import_module(module_name)
    except ImportError as exc:
        raise error_cls(message) from exc


def require_attr(
    module: Any,
    attr_name: str,
    message: str,
    *,
    error_cls: type[Exception],
) -> Any:
    try:
        return getattr(module, attr_name)
    except AttributeError as exc:
        raise error_cls(message) from exc


def load_module_attrs(
    module_name: str,
    missing_module_message: str,
    *,
    attrs: dict[str, str],
    error_cls: type[Exception],
) -> dict[str, Any]:
    module = require_module(
        module_name,
        missing_module_message,
        error_cls=error_cls,
    )
    return {
        attr_name: require_attr(module, attr_name, message, error_cls=error_cls)
        for attr_name, message in attrs.items()
    }


def trazaeo_attr_message(attr_name: str) -> str:
    return f"trazaeo Python bindings do not expose {attr_name}"


def load_trazaeo_attrs(
    *attr_names: str,
    error_cls: type[Exception],
) -> dict[str, Any]:
    return load_module_attrs(
        "trazaeo",
        TRAZAEO_UNAVAILABLE_MESSAGE,
        attrs={attr_name: trazaeo_attr_message(attr_name) for attr_name in attr_names},
        error_cls=error_cls,
    )
