# aiel_sdk/errors.py
from __future__ import annotations

import sys
from typing import Any


# Keep `aiel_sdk.errors` and `src.aiel_sdk.errors` as one module object so
# exceptions are type-identical across either import path.
if __name__ == "src.aiel_sdk.errors":
    sys.modules.setdefault("aiel_sdk.errors", sys.modules[__name__])
elif __name__ == "aiel_sdk.errors":
    sys.modules.setdefault("src.aiel_sdk.errors", sys.modules[__name__])


class AielError(Exception):
    """Base class for AIEL SDK errors."""


class ContractViolation(AielError):
    """User export does not follow required contract/signature."""


class RuntimeDependencyError(AielError):
    """Raised when an optional integration is not installed."""

    def __init__(self, dep: str, hint: str | None = None):
        msg = f"Optional dependency '{dep}' is not installed."
        if hint:
            msg += f" {hint}"
        super().__init__(msg)


class ApiError(AielError):
    """
    Normalized error for any AIEL HTTP call (memory, integrations, etc.).
    """

    def __init__(
        self,
        *,
        service: str,
        status: int,
        message: str,
        code: str | None = None,
        body: Any | None = None,
        request_id: str | None = None,
        url: str | None = None,
    ) -> None:
        parts: list[str] = [f"{service} API error ({status})"]
        if code:
            parts.append(f"code={code}")
        if request_id:
            parts.append(f"request_id={request_id}")
        if url:
            parts.append(f"url={url}")
        parts.append(message)

        details = " | ".join(parts)
        if body is not None:
            details += f" | body={body}"

        super().__init__(details)
        self.service = service
        self.status = status
        self.code = code
        self.body = body
        self.request_id = request_id
        self.url = url
