"""
Error types for the SentryAgent.ai AgentIdP Python SDK.
All API failures are raised as AgentIdPError — never as raw requests/httpx exceptions.
"""

from __future__ import annotations

from typing import Any, Dict, Optional


class AgentIdPError(Exception):
    """
    Typed exception raised for all AgentIdP API failures.

    Attributes:
        code: Machine-readable error code from the API (e.g. ``AgentNotFoundError``).
        http_status: HTTP status code of the failed response.
        details: Optional structured details from the API error response.
    """

    def __init__(
        self,
        code: str,
        message: str,
        http_status: int,
        details: Optional[Dict[str, Any]] = None,
    ) -> None:
        super().__init__(message)
        self.code = code
        self.http_status = http_status
        self.details = details

    def __repr__(self) -> str:
        return (
            f"AgentIdPError(code={self.code!r}, "
            f"http_status={self.http_status}, "
            f"message={str(self)!r})"
        )

    @classmethod
    def from_api_error(
        cls, body: Any, http_status: int
    ) -> "AgentIdPError":
        """
        Create an AgentIdPError from a standard API error response body.

        Args:
            body: Parsed response body (dict or unknown).
            http_status: HTTP status code.

        Returns:
            AgentIdPError instance.
        """
        if isinstance(body, dict) and "code" in body and "message" in body:
            return cls(
                code=str(body["code"]),
                message=str(body["message"]),
                http_status=http_status,
                details=body.get("details"),
            )
        return cls(
            code="UNKNOWN_ERROR",
            message=str(body),
            http_status=http_status,
        )

    @classmethod
    def from_oauth2_error(
        cls, body: Any, http_status: int
    ) -> "AgentIdPError":
        """
        Create an AgentIdPError from an OAuth 2.0 error response body.

        Args:
            body: Parsed response body.
            http_status: HTTP status code.

        Returns:
            AgentIdPError instance.
        """
        if isinstance(body, dict):
            return cls(
                code=str(body.get("error", "unknown_error")),
                message=str(body.get("error_description", "Token request failed.")),
                http_status=http_status,
            )
        return cls(
            code="unknown_error",
            message=str(body),
            http_status=http_status,
        )

    @classmethod
    def network_error(cls, cause: Exception) -> "AgentIdPError":
        """
        Create an AgentIdPError for a network-level failure (no HTTP response).

        Args:
            cause: The underlying exception.

        Returns:
            AgentIdPError with http_status=0.
        """
        return cls(
            code="NETWORK_ERROR",
            message=f"Network error: {cause}",
            http_status=0,
        )
