from typing import Optional, Callable, Type, Dict


error_handlers = {}  # pylint: disable=invalid-name


class BaseHttpError(RuntimeError):
    code = -1
    reason = ''

    def __init__(
            self,
            name: str,
            description: str,
            title: Optional[str] = None,
            extra_fields: Optional[Dict[str, str]] = None) -> None:
        super().__init__()
        # error name for programmers
        self.name = name
        # error description for humans
        self.description = description
        # short title for humans
        self.title = title or self.reason
        # additional fields for programmers
        self.extra_fields = extra_fields


class HttpBadRequest(BaseHttpError):
    code = 400
    reason = 'Bad Request'


class HttpForbidden(BaseHttpError):
    code = 403
    reason = 'Forbidden'


class HttpNotFound(BaseHttpError):
    code = 404
    reason = 'Not Found'


class HttpNotAcceptable(BaseHttpError):
    code = 406
    reason = 'Not Acceptable'


class HttpConflict(BaseHttpError):
    code = 409
    reason = 'Conflict'


class HttpMethodNotAllowed(BaseHttpError):
    code = 405
    reason = 'Method Not Allowed'


class HttpInternalServerError(BaseHttpError):
    code = 500
    reason = 'Internal Server Error'


def handle(
        exception_type: Type[Exception],
        handler: Callable[[Exception], None]) -> None:
    error_handlers[exception_type] = handler
