"""
Audit Log service clients — sync and async.
Covers query (list) and get-by-id operations.
"""

from __future__ import annotations

from typing import Any, Callable, Coroutine, Optional

from .._request import sync_request, async_request
from ..types import AuditAction, AuditEvent, AuditOutcome, PaginatedAuditEvents


class AuditClient:
    """
    Synchronous client for the Audit Log 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 query_audit_log(
        self,
        agent_id: Optional[str] = None,
        action: Optional[AuditAction] = None,
        outcome: Optional[AuditOutcome] = None,
        from_date: Optional[str] = None,
        to_date: Optional[str] = None,
        page: int = 1,
        limit: int = 20,
    ) -> PaginatedAuditEvents:
        """
        Query audit log events with optional filters. Requires ``audit:read`` scope.
        Events are retained for 90 days.

        Args:
            agent_id: Filter by agent UUID.
            action: Filter by audit action type.
            outcome: Filter by outcome (success or failure).
            from_date: ISO 8601 start datetime (inclusive).
            to_date: ISO 8601 end datetime (inclusive).
            page: Page number (1-based).
            limit: Results per page.

        Returns:
            PaginatedAuditEvents response.

        Raises:
            AgentIdPError: On API or network failure.
        """
        data = sync_request(
            "GET", self._base_url, "/api/v1/audit",
            self._get_token(),
            params={
                "agentId": agent_id,
                "action": action,
                "outcome": outcome,
                "fromDate": from_date,
                "toDate": to_date,
                "page": page,
                "limit": limit,
            },
        )
        return PaginatedAuditEvents.from_dict(data)

    def get_audit_event(self, event_id: str) -> AuditEvent:
        """
        Get a single audit event by its eventId. Requires ``audit:read`` scope.

        Args:
            event_id: The audit event UUID.

        Returns:
            AuditEvent record.

        Raises:
            AgentIdPError: On API or network failure.
        """
        data = sync_request(
            "GET", self._base_url, f"/api/v1/audit/{event_id}",
            self._get_token(),
        )
        return AuditEvent.from_dict(data)


class AsyncAuditClient:
    """
    Asynchronous client for the Audit Log 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 query_audit_log(
        self,
        agent_id: Optional[str] = None,
        action: Optional[AuditAction] = None,
        outcome: Optional[AuditOutcome] = None,
        from_date: Optional[str] = None,
        to_date: Optional[str] = None,
        page: int = 1,
        limit: int = 20,
    ) -> PaginatedAuditEvents:
        """Query audit log events with optional filters (async)."""
        data = await async_request(
            "GET", self._base_url, "/api/v1/audit",
            await self._get_token(),
            params={
                "agentId": agent_id,
                "action": action,
                "outcome": outcome,
                "fromDate": from_date,
                "toDate": to_date,
                "page": page,
                "limit": limit,
            },
        )
        return PaginatedAuditEvents.from_dict(data)

    async def get_audit_event(self, event_id: str) -> AuditEvent:
        """Get a single audit event by its eventId (async)."""
        data = await async_request(
            "GET", self._base_url, f"/api/v1/audit/{event_id}",
            await self._get_token(),
        )
        return AuditEvent.from_dict(data)
