"""
Top-level client for the SentryAgent.ai AgentIdP API.
Provides both synchronous (AgentIdPClient) and asynchronous (AsyncAgentIdPClient) variants.
"""

from __future__ import annotations

from typing import List, Optional

from .token_manager import TokenManager
from .async_token_manager import AsyncTokenManager
from .services.agents import AgentRegistryClient, AsyncAgentRegistryClient
from .services.credentials import CredentialClient, AsyncCredentialClient
from .services.token import TokenClient, AsyncTokenClient
from .services.audit import AuditClient, AsyncAuditClient
from .types import OAuthScope

_DEFAULT_SCOPES: List[OAuthScope] = [
    "agents:read",
    "agents:write",
    "tokens:read",
    "audit:read",
]


class AgentIdPClient:
    """
    Synchronous client for the SentryAgent.ai AgentIdP API.

    Composes all service clients under a single entry point. Handles token
    acquisition and caching automatically via :class:`~.token_manager.TokenManager`.

    Args:
        base_url: Base URL of the AgentIdP server (e.g. ``http://localhost:3000``).
        client_id: The agent's ``agentId`` (UUID).
        client_secret: The credential secret.
        scopes: OAuth 2.0 scopes to request. Defaults to all four scopes.

    Example::

        from sentryagent_idp import AgentIdPClient, RegisterAgentRequest

        client = AgentIdPClient(
            base_url="http://localhost:3000",
            client_id="your-agent-id",
            client_secret="your-client-secret",
        )
        agents = client.agents.list_agents()
    """

    def __init__(
        self,
        base_url: str,
        client_id: str,
        client_secret: str,
        scopes: Optional[List[OAuthScope]] = None,
    ) -> None:
        scope_str = " ".join(scopes if scopes is not None else _DEFAULT_SCOPES)
        self._token_manager = TokenManager(base_url, client_id, client_secret, scope_str)

        get_token = self._token_manager.get_token

        #: Agent Registry operations: register, list, get, update, decommission.
        self.agents = AgentRegistryClient(base_url, get_token)
        #: Credential operations: generate, list, rotate, revoke.
        self.credentials = CredentialClient(base_url, get_token)
        #: Token operations: introspect, revoke.
        self.tokens = TokenClient(base_url, get_token)
        #: Audit log operations: query, get event.
        self.audit = AuditClient(base_url, get_token)

    def clear_token_cache(self) -> None:
        """
        Clear the cached access token.
        The next API call will request a new token. Use this after rotating credentials.
        """
        self._token_manager.clear_cache()


class AsyncAgentIdPClient:
    """
    Asynchronous client for the SentryAgent.ai AgentIdP API.

    All methods are coroutines and must be awaited. Token acquisition and caching
    are handled automatically via :class:`~.async_token_manager.AsyncTokenManager`.

    Args:
        base_url: Base URL of the AgentIdP server.
        client_id: The agent's ``agentId`` (UUID).
        client_secret: The credential secret.
        scopes: OAuth 2.0 scopes to request. Defaults to all four scopes.

    Example::

        from sentryagent_idp import AsyncAgentIdPClient

        client = AsyncAgentIdPClient(
            base_url="http://localhost:3000",
            client_id="your-agent-id",
            client_secret="your-client-secret",
        )
        agents = await client.agents.list_agents()
    """

    def __init__(
        self,
        base_url: str,
        client_id: str,
        client_secret: str,
        scopes: Optional[List[OAuthScope]] = None,
    ) -> None:
        scope_str = " ".join(scopes if scopes is not None else _DEFAULT_SCOPES)
        self._token_manager = AsyncTokenManager(base_url, client_id, client_secret, scope_str)

        get_token = self._token_manager.get_token

        #: Agent Registry operations (async).
        self.agents = AsyncAgentRegistryClient(base_url, get_token)
        #: Credential operations (async).
        self.credentials = AsyncCredentialClient(base_url, get_token)
        #: Token operations (async).
        self.tokens = AsyncTokenClient(base_url, get_token)
        #: Audit log operations (async).
        self.audit = AsyncAuditClient(base_url, get_token)

    def clear_token_cache(self) -> None:
        """Clear the cached access token."""
        self._token_manager.clear_cache()
