"""
Structured exception hierarchy for Munal LMS.

All application errors inherit from AppException which produces a consistent
JSON error envelope: { "success": false, "error": { "code": "...", "message": "..." } }

HTTP status codes are set here — routers must never set them manually.
"""

from http import HTTPStatus


class AppException(Exception):
    """
    Base class for all application-level exceptions.

    Attributes:
        status_code: HTTP status code to return to the client.
        code:        Machine-readable error key (e.g. "NOT_FOUND").
        message:     Human-readable message safe to expose to the client.
        detail:      Optional extra context (logged server-side, not always returned).
    """

    status_code: int = HTTPStatus.INTERNAL_SERVER_ERROR
    code: str = "INTERNAL_ERROR"

    def __init__(
        self,
        message: str = "An unexpected error occurred.",
        detail: str | None = None,
    ) -> None:
        self.message = message
        self.detail = detail
        super().__init__(message)


class BadRequestException(AppException):
    """Bad request data or invalid parameter — HTTP 400."""

    status_code = HTTPStatus.BAD_REQUEST
    code = "BAD_REQUEST"

    def __init__(
        self,
        message: str = "Invalid request.",
        detail: str | None = None,
    ) -> None:
        super().__init__(message=message, detail=detail)


class RateLimitException(AppException):
    """Too many requests rate limit exceeded — HTTP 429."""

    status_code = HTTPStatus.TOO_MANY_REQUESTS
    code = "RATE_LIMIT_EXCEEDED"

    def __init__(
        self,
        message: str = "Too many requests. Please try again later.",
        detail: str | None = None,
    ) -> None:
        super().__init__(message=message, detail=detail)


class NotFoundException(AppException):
    """Resource not found — HTTP 404."""

    status_code = HTTPStatus.NOT_FOUND
    code = "NOT_FOUND"

    def __init__(
        self,
        message: str = "The requested resource was not found.",
        detail: str | None = None,
    ) -> None:
        super().__init__(message=message, detail=detail)


class AlreadyExistsException(AppException):
    """Duplicate resource conflict — HTTP 409."""

    status_code = HTTPStatus.CONFLICT
    code = "ALREADY_EXISTS"

    def __init__(
        self,
        message: str = "A resource with the same identifier already exists.",
        detail: str | None = None,
    ) -> None:
        super().__init__(message=message, detail=detail)


ConflictException = AlreadyExistsException


class UnauthorizedException(AppException):
    """Authentication required or credentials invalid — HTTP 401."""

    status_code = HTTPStatus.UNAUTHORIZED
    code = "UNAUTHORIZED"

    def __init__(
        self,
        message: str = "Authentication is required to access this resource.",
        detail: str | None = None,
    ) -> None:
        super().__init__(message=message, detail=detail)


class ForbiddenException(AppException):
    """Authenticated but insufficient permissions — HTTP 403."""

    status_code = HTTPStatus.FORBIDDEN
    code = "FORBIDDEN"

    def __init__(
        self,
        message: str = "You do not have permission to perform this action.",
        detail: str | None = None,
    ) -> None:
        super().__init__(message=message, detail=detail)


class ValidationException(AppException):
    """Business rule validation failure — HTTP 422."""

    status_code = HTTPStatus.UNPROCESSABLE_ENTITY
    code = "VALIDATION_ERROR"

    def __init__(
        self,
        message: str = "The request data failed validation.",
        detail: str | None = None,
    ) -> None:
        super().__init__(message=message, detail=detail)


class ServiceUnavailableException(AppException):
    """External dependency is unavailable — HTTP 503."""

    status_code = HTTPStatus.SERVICE_UNAVAILABLE
    code = "SERVICE_UNAVAILABLE"

    def __init__(
        self,
        message: str = "A required service is temporarily unavailable.",
        detail: str | None = None,
    ) -> None:
        super().__init__(message=message, detail=detail)


class NotImplementedException(AppException):
    """Endpoint or feature not yet implemented — HTTP 501."""

    status_code = HTTPStatus.NOT_IMPLEMENTED
    code = "NOT_IMPLEMENTED"

    def __init__(
        self,
        message: str = "This endpoint is not implemented yet.",
        detail: str | None = None,
    ) -> None:
        super().__init__(message=message, detail=detail)
