from __future__ import annotations

from typing import Any, Mapping, Optional


class SotiError(Exception):
    pass


class SotiValidationError(SotiError):
    def __init__(self, message: str, details: Optional[Mapping[str, Any]] = None):
        super().__init__(message)
        self.message = message
        self.details = dict(details or {})


class SotiConnectionError(SotiError):
    def __init__(self, message: str, *, cause: Optional[BaseException] = None):
        super().__init__(message)
        self.message = message
        self.cause = cause


class SotiAPIError(SotiError):
    def __init__(
        self,
        message: str,
        status_code: Optional[int] = None,
        *,
        code: Optional[str] = None,
        details: Optional[Mapping[str, Any]] = None,
        request_id: Optional[str] = None,
        payload: Any = None,
    ):
        super().__init__(message)
        self.message = message
        self.status_code = status_code
        self.code = code
        self.details = dict(details or {}) if details is not None else None
        self.request_id = request_id
        self.payload = payload

    def __str__(self) -> str:
        parts = [self.message]
        if self.status_code is not None:
            parts.append(f"status={self.status_code}")
        if self.code:
            parts.append(f"code={self.code}")
        return " | ".join(parts)
