"""
Exception-Klassen für Questra Data Client.

Definiert Exceptions für GraphQL-Fehler und Client-Operationen.
Error-Codes werden direkt vom Server übernommen.
"""

from __future__ import annotations


class QuestraError(Exception):
    """Basis-Exception für alle Questra-bezogenen Fehler."""

    pass


class QuestraGraphQLError(QuestraError):
    """
    Exception für GraphQL-Fehler vom Server.

    Der Server liefert strukturierte Fehler mit Error-Codes aus der messageInfos-Liste
    (siehe _systemInfo Query).

    Attributes:
        message: Fehlermeldung vom Server
        code: Error-Code vom Server (z.B. "DATA_MODEL_DUPLICATE_INVENTORY_NAME")
        category: Error-Kategorie (z.B. "DataModel", "Validation", "TimeSeries")
        placeholders: Dictionary mit Platzhalter-Werten aus Extensions
        locations: Liste von Fehler-Positionen im Query
        path: Pfad zum fehlerhaften Feld im Query
        extensions: Vollständige Extensions aus der Error-Response

    Examples:
        >>> try:
        ...     client.mutations.create_inventory(...)
        ... except QuestraGraphQLError as e:
        ...     print(f"Code: {e.code}")
        ...     print(f"Message: {e.message}")
        ...     print(f"Placeholders: {e.placeholders}")
        Code: DATA_MODEL_DUPLICATE_INVENTORY_NAME
        Message: Duplicate inventory name 'TestInventory'...
        Placeholders: {'InventoryName': 'TestInventory', 'NamespaceName': 'Test'}
    """

    def __init__(
        self,
        message: str,
        code: str | None = None,
        category: str | None = None,
        placeholders: dict[str, str] | None = None,
        locations: list[dict] | None = None,
        path: list[str] | None = None,
        extensions: dict | None = None,
    ):
        """
        Initialisiert eine GraphQL-Error-Exception.

        Args:
            message: Fehlermeldung vom Server
            code: Optional - Error-Code
            category: Optional - Error-Kategorie
            placeholders: Optional - Platzhalter-Werte
            locations: Optional - Fehler-Positionen
            path: Optional - Pfad zum Feld
            extensions: Optional - Vollständige Extensions
        """
        super().__init__(message)
        self.message = message
        self.code = code
        self.category = category
        self.placeholders = placeholders or {}
        self.locations = locations or []
        self.path = path or []
        self.extensions = extensions or {}

    def __str__(self) -> str:
        """String-Repräsentation mit Code und Message."""
        if self.code:
            return f"[{self.code}] {self.message}"
        return self.message

    def __repr__(self) -> str:
        """Detaillierte Repräsentation für Debugging."""
        return (
            f"{self.__class__.__name__}("
            f"message={self.message!r}, "
            f"code={self.code!r}, "
            f"category={self.category!r}, "
            f"placeholders={self.placeholders!r})"
        )

    def is_duplicate_error(self) -> bool:
        """Prüft ob es sich um einen Duplicate-Fehler handelt."""
        return self.code is not None and "DUPLICATE" in self.code

    def is_validation_error(self) -> bool:
        """Prüft ob es sich um einen Validierungs-Fehler handelt."""
        return self.category == "Validation"

    def is_not_found_error(self) -> bool:
        """Prüft ob es sich um einen Not-Found-Fehler handelt."""
        return self.code is not None and "UNKNOWN" in self.code


class QuestraAuthenticationError(QuestraError):
    """
    Exception für Authentifizierungs-Fehler.

    Wird geworfen bei fehlgeschlagener Authentifizierung oder ungültigem Token.
    """

    pass
