"""Custom exception hierarchy for the arandu SDK.

All SDK exceptions inherit from ``MemoryError`` so callers can use a single
``except MemoryError`` for catch-all handling, or catch specific subclasses
for granular control.

Each exception supports optional exception chaining via the ``cause`` parameter,
which sets the ``__cause__`` attribute for proper traceback propagation.
"""


class MemoryError(Exception):
    """Base exception for all arandu SDK errors.

    Args:
        message: Human-readable error description.
        cause: Original exception that triggered this error, if any.
    """

    def __init__(self, message: str, *, cause: Exception | None = None) -> None:
        super().__init__(message)
        if cause is not None:
            self.__cause__ = cause


class ExtractionError(MemoryError):
    """Raised when fact/entity extraction from a message fails.

    Args:
        message: Human-readable error description.
        cause: Original exception that triggered this error, if any.
    """


class ResolutionError(MemoryError):
    """Raised when entity resolution fails.

    Args:
        message: Human-readable error description.
        cause: Original exception that triggered this error, if any.
    """


class ReconciliationError(MemoryError):
    """Raised when fact reconciliation against existing knowledge fails.

    Args:
        message: Human-readable error description.
        cause: Original exception that triggered this error, if any.
    """


class RetrievalError(MemoryError):
    """Raised when memory retrieval (semantic search, reranking) fails.

    Args:
        message: Human-readable error description.
        cause: Original exception that triggered this error, if any.
    """


class UpsertError(MemoryError):
    """Raised when upserting facts or entities into the database fails.

    Args:
        message: Human-readable error description.
        cause: Original exception that triggered this error, if any.
    """
