from __future__ import annotations

from collections.abc import Iterable
from typing import NoReturn


class HTTPException(Exception):
    status_code = 500
    default_description = "Internal Server Error"

    def __init__(
        self,
        status_code: int | None = None,
        description: str | None = None,
        headers: dict[str, str] | None = None,
    ) -> None:
        self.status_code = status_code or self.status_code
        self.description = description or self.default_description
        self.headers = headers or {}
        super().__init__(self.description)


class BadRequest(HTTPException):
    status_code = 400
    default_description = "Bad Request"


class NotFound(HTTPException):
    status_code = 404
    default_description = "Not Found"


class MethodNotAllowed(HTTPException):
    status_code = 405
    default_description = "Method Not Allowed"

    def __init__(
        self,
        *,
        allowed_methods: Iterable[str] | None = None,
        description: str | None = None,
    ) -> None:
        methods = sorted({m.upper() for m in (allowed_methods or [])})
        headers = {"Allow": ", ".join(methods)} if methods else {}
        super().__init__(description=description, headers=headers)


class InternalServerError(HTTPException):
    status_code = 500
    default_description = "Internal Server Error"


def abort(status_code: int, description: str | None = None) -> NoReturn:
    raise HTTPException(status_code=status_code, description=description)

