"""Baponi exception hierarchy.

API errors and execution errors are fundamentally different:
- API error (auth failed, rate limited) -> exception raised, no SandboxResult
- Execution error (code threw, non-zero exit) -> SandboxResult with success=False
"""

from __future__ import annotations


class BaponiError(Exception):
    """Base exception for all Baponi API errors."""

    status_code: int
    error_type: str | None
    message: str

    def __init__(
        self,
        message: str,
        *,
        status_code: int = 0,
        error_type: str | None = None,
    ) -> None:
        self.message = message
        self.status_code = status_code
        self.error_type = error_type
        super().__init__(message)

    def __repr__(self) -> str:
        return (
            f"{self.__class__.__name__}("
            f"message={self.message!r}, "
            f"status_code={self.status_code}, "
            f"error_type={self.error_type!r})"
        )


class AuthenticationError(BaponiError):
    """401 Unauthorized. Invalid or missing API key."""


class ForbiddenError(BaponiError):
    """403 Forbidden. API key lacks required permissions."""


class RateLimitError(BaponiError):
    """429 Too Many Requests. Rate limit exceeded.

    Check ``retry_after`` for suggested wait time (may be None if server
    doesn't send Retry-After header).
    """

    retry_after: float | None

    def __init__(
        self,
        message: str,
        *,
        status_code: int = 429,
        error_type: str | None = None,
        retry_after: float | None = None,
    ) -> None:
        super().__init__(message, status_code=status_code, error_type=error_type)
        self.retry_after = retry_after


class ThreadBusyError(BaponiError):
    """409 Conflict. The thread is already executing another request."""


class APITimeoutError(BaponiError):
    """504 Gateway Timeout. Execution timed out on the server.

    Named APITimeoutError (not TimeoutError) to avoid shadowing the Python builtin.
    """


class ServerError(BaponiError):
    """500/503. Internal server error or service temporarily unavailable."""


class APIValidationError(BaponiError):
    """400 Bad Request. Server rejected the request payload.

    Named APIValidationError (not ValidationError) to avoid shadowing Pydantic.
    """
