"""Provider registry + factory.

:func:`get_provider` returns a :class:`~mgf.cloud.providers.base.CloudProvider`.
The ``fake`` provider (in-memory, no deps) is always available; ``infomaniak``
(openstacksdk) and ``aws`` (boto3) load **lazily** via :func:`importlib.import_module`,
so importing ``mgf.cloud`` pulls no SDK and a missing extra (or a not-yet-shipped
adapter) produces a clear, actionable error.
"""

from __future__ import annotations

import importlib
from typing import TYPE_CHECKING

from mgf.cloud.exceptions import ConfigError, CredentialsError, ProviderNotFoundError

if TYPE_CHECKING:
    from mgf.cloud.config import Credentials
    from mgf.cloud.providers.base import CloudProvider

__all__ = ["AVAILABLE_PROVIDERS", "available_providers", "get_provider"]

AVAILABLE_PROVIDERS = ("fake", "infomaniak", "aws")

# name -> (module, class, extra) for the lazily-loaded real providers.
_LAZY_PROVIDERS = {
    "infomaniak": ("mgf.cloud.providers.infomaniak", "InfomaniakProvider", "infomaniak"),
    "aws": ("mgf.cloud.providers.aws", "AwsProvider", "aws"),
}


def available_providers() -> tuple[str, ...]:
    """The provider names :func:`get_provider` accepts."""
    return AVAILABLE_PROVIDERS


def get_provider(name: str, credentials: Credentials | None = None) -> CloudProvider:
    """Return the provider adapter for ``name``.

    ``fake`` needs no credentials; the real providers require ``credentials`` and
    their extra. Raises :class:`ProviderNotFoundError` for an unknown name,
    :class:`CredentialsError` if a real provider is missing credentials, and
    :class:`ConfigError` if the provider's extra/adapter isn't importable.
    """
    if name == "fake":
        from mgf.cloud.providers.fake import FakeProvider

        return FakeProvider()
    if name in _LAZY_PROVIDERS:
        if credentials is None:
            raise CredentialsError(f"the {name!r} provider requires credentials")
        module_path, class_name, extra = _LAZY_PROVIDERS[name]
        try:
            module = importlib.import_module(module_path)
        except ImportError as exc:
            raise ConfigError(
                f"the {name!r} provider needs its extra: pip install 'mgf-cloud[{extra}]'"
            ) from exc
        provider_class = getattr(module, class_name)
        provider: CloudProvider = provider_class(credentials)
        return provider
    raise ProviderNotFoundError(name, AVAILABLE_PROVIDERS)
