"""HTTP and related errors."""
import http
from typing import Any, Dict, cast

from faust.exceptions import FaustError

__all__ = [
    "WebError",
    "ServerError",
    "ValidationError",
    "ParseError",
    "AuthenticationFailed",
    "NotAuthenticated",
    "PermissionDenied",
    "NotFound",
    "MethodNotAllowed",
    "NotAcceptable",
    "UnsupportedMediaType",
    "Throttled",
]


class WebError(FaustError):
    """Web related error.

    Web related errors will have a status :attr:`code`,
    and a :attr:`detail` for the human readable error string.

    It may also keep :attr:`extra_context`.
    """

    code: int = cast(int, None)
    detail: str = "Default not set on class"
    extra_context: Dict

    def __init__(
        self, detail: str = None, *, code: int = None, **extra_context: Any
    ) -> None:
        if detail:
            self.detail = detail
        if code:
            self.code = code
        self.extra_context = extra_context
        super().__init__(self, detail, code, extra_context)


class ServerError(WebError):
    """Internal Server Error (500)."""

    code = http.HTTPStatus.INTERNAL_SERVER_ERROR
    detail = "Internal server error."


class ValidationError(WebError):
    """Invalid input in POST data (400)."""

    code = http.HTTPStatus.BAD_REQUEST
    detail = "Invalid input."


class ParseError(WebError):
    """Malformed request (400)."""

    code = http.HTTPStatus.BAD_REQUEST
    detail = "Malformed request."


class AuthenticationFailed(WebError):
    """Incorrect authentication credentials (401)."""

    code = http.HTTPStatus.UNAUTHORIZED
    detail = "Incorrect authentication credentials"


class NotAuthenticated(WebError):
    """Authentication credentials were not provided (401)."""

    code = http.HTTPStatus.UNAUTHORIZED
    detail = "Authentication credentials were not provided."


class PermissionDenied(WebError):
    """No permission to perform action (403)."""

    code = http.HTTPStatus.FORBIDDEN
    detail = "You do not have permission to perform this action."


class NotFound(WebError):
    """Resource not found (404)."""

    code = http.HTTPStatus.NOT_FOUND
    detail = "Not found."


class MethodNotAllowed(WebError):
    """HTTP Method not allowed (405)."""

    code = http.HTTPStatus.METHOD_NOT_ALLOWED
    detail = "Method not allowed."


class NotAcceptable(WebError):
    """Not able to satisfy the request ``Accept`` header (406)."""

    code = http.HTTPStatus.NOT_ACCEPTABLE
    detail = "Could not satisfy the request Accept header."


class UnsupportedMediaType(WebError):
    """Request contains unsupported media type (415)."""

    code = http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE
    detail = "Unsupported media type in request."


class Throttled(WebError):
    """Client is sending too many requests to server (429)."""

    code = http.HTTPStatus.TOO_MANY_REQUESTS
    detail = "Request was throttled."


class ServiceUnavailable(WebError):
    """Service is temporarily unavailable (503)."""

    code = http.HTTPStatus.SERVICE_UNAVAILABLE
    detail = "Service unavailable. Try again later."
