"""
Agent Registry service clients — sync and async.
Covers all five agent endpoints: register, list, get, update, decommission.
"""

from __future__ import annotations

from typing import Any, Callable, Coroutine, Dict, Optional

from .._request import sync_request, async_request
from ..types import (
    Agent,
    AgentStatus,
    AgentType,
    PaginatedAgents,
    RegisterAgentRequest,
    UpdateAgentRequest,
)


class AgentRegistryClient:
    """
    Synchronous client for the Agent Registry service.

    Args:
        base_url: AgentIdP server base URL.
        get_token: Callable that returns a valid Bearer token.
    """

    def __init__(
        self,
        base_url: str,
        get_token: Callable[[], str],
    ) -> None:
        self._base_url = base_url
        self._get_token = get_token

    def register_agent(self, request: RegisterAgentRequest) -> Agent:
        """
        Register a new AI agent.

        Args:
            request: Agent registration parameters.

        Returns:
            The created Agent record.

        Raises:
            AgentIdPError: On API or network failure.
        """
        data = sync_request(
            "POST", self._base_url, "/api/v1/agents",
            self._get_token(), body=request.to_dict(),
        )
        return Agent.from_dict(data)

    def list_agents(
        self,
        status: Optional[AgentStatus] = None,
        agent_type: Optional[AgentType] = None,
        page: int = 1,
        limit: int = 20,
    ) -> PaginatedAgents:
        """
        List all registered agents with optional filters.

        Args:
            status: Filter by lifecycle status.
            agent_type: Filter by agent type.
            page: Page number (1-based).
            limit: Results per page.

        Returns:
            PaginatedAgents response.

        Raises:
            AgentIdPError: On API or network failure.
        """
        data = sync_request(
            "GET", self._base_url, "/api/v1/agents",
            self._get_token(),
            params={"status": status, "agentType": agent_type, "page": page, "limit": limit},
        )
        return PaginatedAgents.from_dict(data)

    def get_agent(self, agent_id: str) -> Agent:
        """
        Get a single agent by its agentId.

        Args:
            agent_id: The agent UUID.

        Returns:
            Agent record.

        Raises:
            AgentIdPError: If agent not found or network failure.
        """
        data = sync_request(
            "GET", self._base_url, f"/api/v1/agents/{agent_id}",
            self._get_token(),
        )
        return Agent.from_dict(data)

    def update_agent(self, agent_id: str, request: UpdateAgentRequest) -> Agent:
        """
        Update mutable fields on an existing agent.

        Args:
            agent_id: The agent UUID.
            request: Fields to update.

        Returns:
            Updated Agent record.

        Raises:
            AgentIdPError: On API or network failure.
        """
        data = sync_request(
            "PATCH", self._base_url, f"/api/v1/agents/{agent_id}",
            self._get_token(), body=request.to_dict(),
        )
        return Agent.from_dict(data)

    def decommission_agent(self, agent_id: str) -> None:
        """
        Decommission an agent. This is irreversible.

        Args:
            agent_id: The agent UUID.

        Raises:
            AgentIdPError: On API or network failure.
        """
        sync_request(
            "DELETE", self._base_url, f"/api/v1/agents/{agent_id}",
            self._get_token(),
        )


class AsyncAgentRegistryClient:
    """
    Asynchronous client for the Agent Registry service.

    Args:
        base_url: AgentIdP server base URL.
        get_token: Async callable that returns a valid Bearer token.
    """

    def __init__(
        self,
        base_url: str,
        get_token: Callable[[], Coroutine[Any, Any, str]],
    ) -> None:
        self._base_url = base_url
        self._get_token = get_token

    async def register_agent(self, request: RegisterAgentRequest) -> Agent:
        """Register a new AI agent (async)."""
        data = await async_request(
            "POST", self._base_url, "/api/v1/agents",
            await self._get_token(), body=request.to_dict(),
        )
        return Agent.from_dict(data)

    async def list_agents(
        self,
        status: Optional[AgentStatus] = None,
        agent_type: Optional[AgentType] = None,
        page: int = 1,
        limit: int = 20,
    ) -> PaginatedAgents:
        """List all registered agents with optional filters (async)."""
        data = await async_request(
            "GET", self._base_url, "/api/v1/agents",
            await self._get_token(),
            params={"status": status, "agentType": agent_type, "page": page, "limit": limit},
        )
        return PaginatedAgents.from_dict(data)

    async def get_agent(self, agent_id: str) -> Agent:
        """Get a single agent by its agentId (async)."""
        data = await async_request(
            "GET", self._base_url, f"/api/v1/agents/{agent_id}",
            await self._get_token(),
        )
        return Agent.from_dict(data)

    async def update_agent(self, agent_id: str, request: UpdateAgentRequest) -> Agent:
        """Update mutable fields on an existing agent (async)."""
        data = await async_request(
            "PATCH", self._base_url, f"/api/v1/agents/{agent_id}",
            await self._get_token(), body=request.to_dict(),
        )
        return Agent.from_dict(data)

    async def decommission_agent(self, agent_id: str) -> None:
        """Decommission an agent — irreversible (async)."""
        await async_request(
            "DELETE", self._base_url, f"/api/v1/agents/{agent_id}",
            await self._get_token(),
        )
