# Code generated by stigmer-codegen. DO NOT EDIT.

from __future__ import annotations

import enum

import grpc


class ErrorCode(enum.Enum):
    """Error codes mapped from gRPC status codes."""

    UNKNOWN = "unknown"
    NOT_FOUND = "not-found"
    PERMISSION_DENIED = "permission-denied"
    UNAUTHENTICATED = "unauthenticated"
    INVALID_ARGUMENT = "invalid-argument"
    ALREADY_EXISTS = "already-exists"
    RESOURCE_EXHAUSTED = "resource-exhausted"
    FAILED_PRECONDITION = "failed-precondition"
    INTERNAL = "internal"
    UNAVAILABLE = "unavailable"
    CANCELLED = "cancelled"


_GRPC_CODE_MAP: dict[grpc.StatusCode, ErrorCode] = {
    grpc.StatusCode.NOT_FOUND: ErrorCode.NOT_FOUND,
    grpc.StatusCode.PERMISSION_DENIED: ErrorCode.PERMISSION_DENIED,
    grpc.StatusCode.UNAUTHENTICATED: ErrorCode.UNAUTHENTICATED,
    grpc.StatusCode.INVALID_ARGUMENT: ErrorCode.INVALID_ARGUMENT,
    grpc.StatusCode.ALREADY_EXISTS: ErrorCode.ALREADY_EXISTS,
    grpc.StatusCode.RESOURCE_EXHAUSTED: ErrorCode.RESOURCE_EXHAUSTED,
    grpc.StatusCode.FAILED_PRECONDITION: ErrorCode.FAILED_PRECONDITION,
    grpc.StatusCode.INTERNAL: ErrorCode.INTERNAL,
    grpc.StatusCode.UNAVAILABLE: ErrorCode.UNAVAILABLE,
    grpc.StatusCode.CANCELLED: ErrorCode.CANCELLED,
}


class StigmerError(Exception):
    """Structured error type returned by all SDK operations."""

    def __init__(
        self,
        code: ErrorCode,
        message: str,
        grpc_code: grpc.StatusCode,
    ) -> None:
        super().__init__(message)
        self.code = code
        self.grpc_code = grpc_code

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


def wrap_error(err: grpc.RpcError) -> StigmerError:
    """Convert a gRPC RpcError into a StigmerError."""
    grpc_code = err.code()
    code = _GRPC_CODE_MAP.get(grpc_code, ErrorCode.UNKNOWN)
    message = err.details() or str(err)
    return StigmerError(code, message, grpc_code)


def is_not_found(err: BaseException) -> bool:
    """Check whether an error represents a NOT_FOUND status."""
    return isinstance(err, StigmerError) and err.code == ErrorCode.NOT_FOUND


def is_unauthenticated(err: BaseException) -> bool:
    """Check whether an error represents an UNAUTHENTICATED status."""
    return isinstance(err, StigmerError) and err.code == ErrorCode.UNAUTHENTICATED


def is_permission_denied(err: BaseException) -> bool:
    """Check whether an error represents a PERMISSION_DENIED status."""
    return isinstance(err, StigmerError) and err.code == ErrorCode.PERMISSION_DENIED


def is_retryable(err: BaseException) -> bool:
    """Check whether the error is transient and the operation can be retried."""
    return isinstance(err, StigmerError) and err.code in (
        ErrorCode.INTERNAL,
        ErrorCode.UNAVAILABLE,
    )
