"""Custom exception classes for ACP error codes."""


class ACPError(Exception):
    """Base exception for ACP protocol errors."""

    def __init__(self, code: str, message: str, status_code: int, detail: dict | None = None):
        self.code = code
        self.message = message
        self.status_code = status_code
        self.detail = detail or {}
        super().__init__(f"[{code}] {message}")


class InvalidRequestError(ACPError):
    """Invalid request parameters."""
    pass


class AuthenticationError(ACPError):
    """Authentication or signature verification failed."""
    pass


class BudgetError(ACPError):
    """Budget limit exceeded or authorization expired."""
    pass


class NotFoundError(ACPError):
    """Resource not found."""
    pass


class ConflictError(ACPError):
    """Resource conflict (already exists, wallet already bound, etc.)."""
    pass


class RateLimitError(ACPError):
    """Rate limit exceeded."""
    pass


class WalletRequiredError(ACPError):
    """Wallet binding required before this operation."""
    pass


# Map ACP error codes to exception classes
_ERROR_MAP: dict[str, type[ACPError]] = {
    'INVALID_REQUEST': InvalidRequestError,
    'INVALID_DESCRIPTOR': InvalidRequestError,
    'INVALID_SIGNATURE': AuthenticationError,
    'NONCE_REUSED': AuthenticationError,
    'AUTHORIZATION_EXPIRED': BudgetError,
    'BUDGET_RULE_VIOLATED': BudgetError,
    'INSUFFICIENT_BUDGET': BudgetError,
    'APPROVAL_REQUIRED': BudgetError,
    'SERVICE_NOT_FOUND': NotFoundError,
    'AGENT_NOT_FOUND': NotFoundError,
    'SERVICE_ALREADY_EXISTS': ConflictError,
    'WALLET_ALREADY_BOUND': ConflictError,
    'WALLET_IN_USE': ConflictError,
    'WALLET_REQUIRED': WalletRequiredError,
    'RATE_LIMITED': RateLimitError,
    'TIMESTAMP_EXPIRED': AuthenticationError,
}


def raise_for_acp_error(status_code: int, body: dict) -> None:
    """Parse ACP error response and raise the appropriate exception."""
    error = body.get('error', body)
    code = error.get('code', 'UNKNOWN')
    message = error.get('message', 'Unknown error')

    exc_class = _ERROR_MAP.get(code, ACPError)
    raise exc_class(code=code, message=message, status_code=status_code, detail=error)
