"""Exception hierarchy for the Appliku SDK."""

from __future__ import annotations


class AplikuError(Exception):
    """Base exception for all Appliku errors."""

    def __init__(
        self,
        message: str,
        status_code: int | None = None,
        response: dict[str, object] | None = None,
    ) -> None:
        super().__init__(message)
        self.status_code = status_code
        self.response = response


class AuthenticationError(AplikuError):
    """Authentication failed (401)."""


class AuthorizationError(AplikuError):
    """Access denied (403)."""


class NotFoundError(AplikuError):
    """Resource not found (404)."""


class ValidationError(AplikuError):
    """Request validation failed (400)."""


class RateLimitError(AplikuError):
    """Rate limit exceeded (429)."""


class ServerError(AplikuError):
    """Server-side error (5xx)."""


def parse_error_response(status_code: int, body: dict[str, object]) -> AplikuError:
    """Factory: maps status code + DRF error shapes to the right exception.

    Handles three DRF shapes:
    - {"detail": "message"}
    - {"non_field_errors": ["msg"]}
    - {"field": ["error1", ...]}
    """
    # Extract human-readable message
    if "detail" in body:
        message = str(body["detail"])
    elif "non_field_errors" in body:
        errors = body["non_field_errors"]
        message = "; ".join(str(e) for e in errors) if isinstance(errors, list) else str(errors)
    else:
        # Field-level errors: {"field": ["error1", ...]}
        parts: list[str] = []
        for key, value in body.items():
            if isinstance(value, list):
                parts.append(f"{key}: {', '.join(str(v) for v in value)}")
            else:
                parts.append(f"{key}: {value}")
        message = "; ".join(parts) if parts else str(body)

    exc_class: type[AplikuError]
    if status_code == 400:
        exc_class = ValidationError
    elif status_code == 401:
        exc_class = AuthenticationError
    elif status_code == 403:
        exc_class = AuthorizationError
    elif status_code == 404:
        exc_class = NotFoundError
    elif status_code == 429:
        exc_class = RateLimitError
    elif status_code >= 500:
        exc_class = ServerError
    else:
        exc_class = AplikuError

    return exc_class(message, status_code=status_code, response=body)
