"""Python SDK for the Partner Ecosystem.

JWKS-based auth verification and server-to-server actions, mirroring the
``ab-ecosystem-node`` package.

Example
-------
    from ab_ecosystem import init, get_user_profile

    init(api_url="https://api.example.com", project_id="proj_123", project_secret="secret")

    profile = get_user_profile(access_token=user_jwt)
"""

from __future__ import annotations

from typing import Any, Mapping, Optional, Union

from .auth import Audience, TokenVerifier, extract_bearer_token
from .client import PartnerEcosystemClient
from .config import ResolvedConfig
from .errors import ApiError
from .types import DeductionRequest, JwksOptions, PartnerEcosystemConfig

__all__ = [
    "init",
    "get_instance",
    "get_user_profile",
    "get_user_wallet",
    "get_user_credit_wallet",
    "get_user_subscription",
    "send_deduction_request",
    "verify_token",
    "ping",
    "PartnerEcosystemClient",
    "PartnerEcosystemConfig",
    "DeductionRequest",
    "JwksOptions",
    "ResolvedConfig",
    "TokenVerifier",
    "ApiError",
    "extract_bearer_token",
]

__version__ = "0.1.2"

#: The process-wide singleton created by :func:`init`.
_instance: Optional[PartnerEcosystemClient] = None


def init(
    config: Optional[PartnerEcosystemConfig] = None,
    *,
    api_url: Optional[str] = None,
    project_id: Optional[str] = None,
    project_secret: Optional[str] = None,
    jwks_path: str = "/.well-known/jwks.json",
    issuer: Optional[str] = None,
    audience: Optional[str] = None,
    jwks: Optional[JwksOptions] = None,
) -> PartnerEcosystemClient:
    """Initialise the SDK. Call once at start-up.

    Accepts either a :class:`PartnerEcosystemConfig` instance or keyword
    arguments. The created client is stored as a process-wide singleton, so the
    returned value and the module-level helpers all share it.
    """
    global _instance

    if config is None:
        if api_url is None or project_id is None or project_secret is None:
            raise ValueError(
                "[partner-ecosystem] init() requires api_url, project_id and "
                "project_secret (or a PartnerEcosystemConfig instance)."
            )
        config = PartnerEcosystemConfig(
            api_url=api_url,
            project_id=project_id,
            project_secret=project_secret,
            jwks_path=jwks_path,
            issuer=issuer,
            audience=audience,
            jwks=jwks,
        )

    _instance = PartnerEcosystemClient(config)
    return _instance


def get_instance() -> PartnerEcosystemClient:
    """Access the singleton created by :func:`init`.

    Raises ``RuntimeError`` if :func:`init` has not been called yet.
    """
    if _instance is None:
        raise RuntimeError(
            "[partner-ecosystem] SDK not initialised. Call init(...) before using the SDK."
        )
    return _instance


def get_user_profile(
    access_token: Optional[str] = None, user_id: Optional[str] = None
) -> Any:
    """Fetch the current user's profile via the singleton client."""
    return get_instance().get_user_profile(access_token, user_id)


def get_user_wallet(
    access_token: Optional[str] = None, user_id: Optional[str] = None
) -> Any:
    """Fetch the current user's wallet via the singleton client."""
    return get_instance().get_user_wallet(access_token, user_id)


def get_user_credit_wallet(
    access_token: Optional[str] = None, user_id: Optional[str] = None
) -> Any:
    """Fetch the current user's credit wallet(s) via the singleton client."""
    return get_instance().get_user_credit_wallet(access_token, user_id)


def get_user_subscription(
    access_token: Optional[str] = None, user_id: Optional[str] = None
) -> Any:
    """Fetch the current user's subscription via the singleton client."""
    return get_instance().get_user_subscription(access_token, user_id)


def send_deduction_request(
    wallet_id: str,
    payload: Union[DeductionRequest, Mapping[str, Any]],
    access_token: Optional[str] = None,
    user_id: Optional[str] = None,
) -> Any:
    """Send a deduction request against a credit wallet via the singleton client."""
    return get_instance().send_deduction_request(
        wallet_id, payload, access_token, user_id
    )


def verify_token(
    token: str,
    *,
    audience: Optional[Audience] = None,
    issuer: Optional[str] = None,
) -> dict:
    """Verify a bearer JWT via the singleton client."""
    return get_instance().verify_token(token, audience=audience, issuer=issuer)


def ping() -> Any:
    """Health check via the singleton client."""
    return get_instance().ping()
