"""
Response classes for every HTTP status code (RFC 9110).

Spec: https://www.rfc-editor.org/rfc/rfc9110.html

Each class is a `HttpResponse <https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.HttpResponse>`_ subclass. They're listed
here by status range:

**1xx Informational** — request received, continuing
  :class:`HttpResponseContinue` (100), :class:`HttpResponseSwitchingProtocols` (101)

**2xx Success** — request succeeded
  :class:`HttpResponseOK` (200), :class:`HttpResponseCreated` (201),
  :class:`HttpResponseAccepted` (202),
  :class:`HttpResponseNonAuthoritativeInformation` (203),
  :class:`HttpResponseNoContent` (204), :class:`HttpResponseResetContent` (205),
  :class:`HttpResponsePartialContent` (206)

**3xx Redirection** — client should take another action
  :class:`HttpResponseMultipleChoices` (300),
  :class:`HttpResponsePermanentRedirect` (301), :class:`HttpResponseRedirect` (302),
  :class:`HttpResponseSeeOther` (303), :class:`HttpResponseNotModified` (304),
  :class:`HttpResponseUseProxy` (305), :class:`HttpResponseTemporaryRedirect` (307),
  :class:`HttpResponsePermanentRedirect308` (308)

**4xx Client Error** — something wrong with the request
  :class:`HttpResponseBadRequest` (400), :class:`HttpResponseUnauthorized` (401),
  :class:`HttpResponsePaymentRequired` (402),
  :class:`HttpResponseForbidden` (403), :class:`HttpResponseNotFound` (404),
  :class:`HttpResponseNotAllowed` (405), :class:`HttpResponseNotAcceptable` (406),
  :class:`HttpResponseProxyAuthenticationRequired` (407),
  :class:`HttpResponseRequestTimeout` (408), :class:`HttpResponseConflict` (409),
  :class:`HttpResponseGone` (410), :class:`HttpResponseLengthRequired` (411),
  :class:`HttpResponsePreconditionFailed` (412),
  :class:`HttpResponseContentTooLarge` (413), :class:`HttpResponseUriTooLong` (414),
  :class:`HttpResponseUnsupportedMediaType` (415),
  :class:`HttpResponseRangeNotSatisfiable` (416),
  :class:`HttpResponseExpectationFailed` (417),
  :class:`HttpResponseMisdirectedRequest` (421),
  :class:`HttpResponseUnprocessableContent` (422),
  :class:`HttpResponseUpgradeRequired` (426)

**5xx Server Error** — server failed to fulfill the request
  :class:`HttpResponseServerError` (500), :class:`HttpResponseNotImplemented` (501),
  :class:`HttpResponseBadGateway` (502), :class:`HttpResponseServiceUnavailable` (503),
  :class:`HttpResponseGatewayTimeout` (504),
  :class:`HttpResponseHttpVersionNotSupported` (505)

See each class's docstring for when to use it.
"""

from __future__ import annotations

from datetime import datetime
from email.utils import formatdate
from typing import Any, Iterable

from django.http import (
    HttpResponse,
    HttpResponseBadRequest as _HttpResponseBadRequest,
    HttpResponseForbidden as _HttpResponseForbidden,
    HttpResponseGone as _HttpResponseGone,
    HttpResponseNotFound as _HttpResponseNotFound,
    HttpResponseNotModified as _HttpResponseNotModified,
    HttpResponsePermanentRedirect as _HttpResponsePermanentRedirect,
    HttpResponseRedirect as _HttpResponseRedirect,
    HttpResponseServerError as _HttpResponseServerError,
)


def retry_after_value(retry_after: int | float | datetime) -> str:
    """Return the Retry-After header value for the given delay.

    Use with 408, 413, 503, or 3xx responses when the client may retry later.

    Args:
        retry_after: Seconds (int/float) or a datetime (UTC if naive).

    Returns:
        str: The header value (delay-seconds or HTTP-date).

    Example::

        response = HttpResponseServiceUnavailable()
        response["Retry-After"] = retry_after_value(120)
    """
    if isinstance(retry_after, (int, float)):
        return str(int(retry_after))
    if hasattr(retry_after, "timestamp"):
        return formatdate(retry_after.timestamp(), usegmt=True)
    raise TypeError("retry_after must be a number of seconds (int/float) or a datetime")


def set_content_location(response: HttpResponse, uri: str) -> None:
    """Set the Content-Location header on a response.

    Use with 200, 201, 206, or 304 when the response body corresponds to
    a specific resource URI (e.g. after content negotiation).

    Args:
        response: An HttpResponse instance.
        uri: Absolute or partial URI for the representation.
    """
    response["Content-Location"] = uri


# ---------------------------------------------------------------------------
# 1xx Informational
# ---------------------------------------------------------------------------


class HttpResponseContinue(HttpResponse):
    """100 Continue.

    Tell the client to keep sending the request body (used with
    Expect: 100-continue). The response has no body.

    Note: Usually handled by the web server or proxy, not in Django views.
    """

    status_code = 100


class HttpResponseSwitchingProtocols(HttpResponse):
    """101 Switching Protocols.

    Tell the client you're switching protocol on this connection (e.g. to
    WebSocket). Pass ``upgrade`` to set the Upgrade header (and
    Connection: Upgrade).

    Args:
        upgrade: Protocol name(s), e.g. ``"websocket"`` or
            ``["HTTP/3.0", "websocket"]``. Sets Upgrade and Connection headers.

    Note: Usually done by the web server or reverse proxy, not in Django.
    """

    status_code = 101

    def __init__(
        self,
        upgrade: str | Iterable[str] | None = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        if upgrade is not None:
            if isinstance(upgrade, str):
                upgrade = [upgrade]
            self["Upgrade"] = ", ".join(upgrade)
            self["Connection"] = "Upgrade"


# ---------------------------------------------------------------------------
# 2xx Success
# ---------------------------------------------------------------------------


class HttpResponseOK(HttpResponse):
    """200 OK.

    The request succeeded. Use this for a normal response with a body.
    Use 204 when there's nothing to send in the body.

    Example::

        return HttpResponseOK("<p>Saved.</p>")
    """

    status_code = 200


class HttpResponseCreated(HttpResponse):
    """201 Created.

    Use when you created a new resource. Pass the resource's URL as
    ``location``; it's sent as the Location header.

    Args:
        location: URL of the new resource.
        content_location: Optional. URI of the representation (e.g. same as
            location). Sets Content-Location.

    Example::

        return HttpResponseCreated(
            location=request.build_absolute_uri(obj.get_absolute_url())
        )
    """

    status_code = 201

    def __init__(
        self,
        location: str,
        content_location: str | None = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        self["Location"] = location
        if content_location is not None:
            self["Content-Location"] = content_location


class HttpResponseAccepted(HttpResponse):
    """202 Accepted.

    Use when you've accepted the request but haven't finished (e.g. you
    queued a background job). The client can't assume the action will
    succeed.

    Example::

        queue_export_task(project_id)
        return HttpResponseAccepted()
    """

    status_code = 202


class HttpResponseNonAuthoritativeInformation(HttpResponse):
    """203 Non-Authoritative Information.

    Use when a proxy modified the response (e.g. transcoding, anonymizing).
    Tells the client the body isn't the origin server's exact 200 response.

    Example::

        return HttpResponseNonAuthoritativeInformation(transformed_content)
    """

    status_code = 203


class HttpResponseNoContent(HttpResponse):
    """204 No Content.

    Success, but no response body (e.g. after a delete or save). This class
    strips Content-Type and blocks you from setting content.

    Example::

        item.delete()
        return HttpResponseNoContent()
    """

    status_code = 204

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        kwargs.pop("content", None)
        if args:
            args = args[1:]  # drop first positional (content)
        super().__init__(*args, **kwargs)
        del self["Content-Type"]
        self._container = []

    @HttpResponse.content.setter
    def content(self, value: Any) -> None:
        if value:
            raise AttributeError(
                "You cannot set content to a 204 (No Content) response"
            )
        self._container = []


class HttpResponseResetContent(HttpResponse):
    """205 Reset Content.

    Success; tell the client to reset the form/view so the user can enter
    again (e.g. after submitting a form). No body allowed; this class
    enforces that like 204.

    Example::

        return HttpResponseResetContent()
    """

    status_code = 205

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        kwargs.pop("content", None)
        if args:
            args = args[1:]  # drop first positional (content)
        super().__init__(*args, **kwargs)
        del self["Content-Type"]
        self._container = []

    @HttpResponse.content.setter
    def content(self, value: Any) -> None:
        if value:
            raise AttributeError(
                "You cannot set content to a 205 (Reset Content) response"
            )
        self._container = []


class HttpResponsePartialContent(HttpResponse):
    """206 Partial Content.

    Use for range requests (Range header). Send the byte range as body
    and set a Content-Range header. Pass ``content_range`` as
    ``(start, end, total)`` or a full string (e.g. ``"bytes 0-1023/2048"``).
    Optional ``content_location`` sets Content-Location.

    Args:
        content: The partial byte range as body.
        content_range: Optional. Either ``(start, end, total)`` for bytes, or
            a full Content-Range string (e.g. ``"bytes 0-1023/2048"``).
        content_location: Optional. URI of the representation. Sets
            Content-Location.

    Example::

        return HttpResponsePartialContent(
            partial_bytes,
            content_range=(0, 1023, 2048),
        )
    """

    status_code = 206

    def __init__(
        self,
        content: str | bytes = b"",
        content_range: tuple[int, int, int] | str | None = None,
        content_location: str | None = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(content, *args, **kwargs)
        if content_range is not None:
            if isinstance(content_range, (list, tuple)) and len(content_range) == 3:
                start, end, total = content_range
                self["Content-Range"] = f"bytes {start}-{end}/{total}"
            else:
                self["Content-Range"] = content_range
        if content_location is not None:
            self["Content-Location"] = content_location


# ---------------------------------------------------------------------------
# 3xx Redirection
# ---------------------------------------------------------------------------


class HttpResponseMultipleChoices(HttpResponse):
    """300 Multiple Choices.

    Use when the resource has several representations (e.g. languages).
    Send a list of options in the body or via Link headers; optional
    Location for a preferred choice.

    Example::

        return HttpResponseMultipleChoices(
            "<ul><li><a href='/fr/'>French</a></li></ul>",
            content_type="text/html",
        )
    """

    status_code = 300


class HttpResponseMovedPermanently(_HttpResponsePermanentRedirect):
    """301 Moved Permanently.

    The resource has a new permanent URL. Browsers may cache this and
    change POST to GET on redirect; use 308 if you need the method kept.
    308 ()

    Example::

        return HttpResponsePermanentRedirect(new_url)
    """

    pass


class HttpResponseFound(_HttpResponseRedirect):
    """302 Found.

    Temporary redirect to another URL. Browsers may change POST to GET;
    use 307 if you need the method preserved.

    Example::

        return HttpResponseRedirect(new_url)
    """

    pass


class HttpResponseSeeOther(HttpResponse):
    """303 See Other.

    Redirect the client to another URL with a GET request (e.g. after
    POST). The response to the new URL is the result of the request.
    Use 302 for a generic temporary redirect.

    Example::

        return HttpResponseSeeOther(new_url)
    """

    status_code = 303

    def __init__(
        self,
        redirect_to: str,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        self["Location"] = redirect_to


class HttpResponseNotModified(_HttpResponseNotModified):
    """304 Not Modified.

    Use when a conditional request (If-None-Match, If-Modified-Since)
    shows the client's copy is still valid. No body; this class strips
    Content-Type and blocks you from setting content.

    Example::

        return HttpResponseNotModified()
    """

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        kwargs.pop("content", None)
        if args:
            args = args[1:]
        super().__init__(*args, **kwargs)
        if "Content-Type" in self:
            del self["Content-Type"]
        self._container = []

    @HttpResponse.content.setter
    def content(self, value: Any) -> None:
        if value:
            raise AttributeError(
                "You cannot set content to a 304 (Not Modified) response"
            )
        self._container = []


class HttpResponseUseProxy(HttpResponse):
    """305 Use Proxy.

    Resource is only available via a proxy. Pass ``location`` with the
    proxy URI. Deprecated; many clients ignore it. Prefer configuring
    the proxy at the server level.

    Args:
        location: Optional. URI of the proxy to use.
    """

    status_code = 305

    def __init__(
        self,
        location: str | None = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        if location is not None:
            self["Location"] = location


class HttpResponseTemporaryRedirect(HttpResponse):
    """307 Temporary Redirect.

    Temporary redirect; the client MUST preserve the request method (POST
    stays POST). Use 302 when you're fine with browsers converting POST
    to GET.

    Example::

        return HttpResponseTemporaryRedirect(redirect_to)
    """

    status_code = 307

    def __init__(
        self,
        redirect_to: str,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        self["Location"] = redirect_to


class HttpResponsePermanentRedirect(HttpResponse):
    """308 Permanent Redirect.

    Permanent redirect; the client MUST preserve the request method (POST
    stays POST). Use 301 when you're fine with browsers converting POST
    to GET and caching the redirect.

    Example::

        return HttpResponsePermanentRedirect308(redirect_to)
    """

    status_code = 308

    def __init__(
        self,
        redirect_to: str,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        self["Location"] = redirect_to


# ---------------------------------------------------------------------------
# 4xx Client Error
# ---------------------------------------------------------------------------


class HttpResponseBadRequest(_HttpResponseBadRequest):
    """400 Bad Request.

    Use when the request is malformed or invalid (bad syntax, invalid
    JSON, etc.).

    Example::

        return HttpResponseBadRequest("Invalid JSON body")
    """

    pass


class HttpResponseUnauthorized(HttpResponse):
    """401 Unauthorized.

    Use when the client must authenticate (missing or invalid credentials).
    You MUST send a WWW-Authenticate header; the client may retry with
    Authorization.

    Example::

        response = HttpResponseUnauthorized()
        response["WWW-Authenticate"] = 'Basic realm="API"'
        return response
    """

    status_code = 401


class HttpResponsePaymentRequired(HttpResponse):
    """402 Payment Required.

    Use when the client must pay or subscribe before accessing the
    resource (e.g. quota exceeded, subscription required).

    Example::

        return HttpResponsePaymentRequired()
    """

    status_code = 402


class HttpResponseForbidden(_HttpResponseForbidden):
    """403 Forbidden.

    Use when the user isn't -owed to do this (auth succeeded but
    permission denied). Use 404 instead if you want to hide that the
    resource exists.

    Example::

        return HttpResponseForbidden("You cannot edit this resource")
    """

    pass


class HttpResponseNotFound(_HttpResponseNotFound):
    """404 Not Found.

    Use when the resource doesn't exist (or you don't want to reveal it).
    Use 410 Gone if it used to exist and is permanently removed.

    Example::

        return HttpResponseNotFound()
    """

    pass


class HttpResponseNotAllowed(HttpResponse):
    """405 Method Not Allowed.

    Use when the HTTP method isn't allowed for this resource (e.g. POST
    to a read-only URL). Pass the list of allowed methods; this class
    sets the Allow header for you.

    Args:
        permitted_methods: Allowed methods, e.g. ``["GET", "HEAD"]``.

    Example::

        return HttpResponseNotAllowed(["GET", "HEAD"])
    """

    status_code = 405

    def __init__(
        self,
        permitted_methods: Iterable[str],
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        self["Allow"] = ", ".join(str(m).upper() for m in permitted_methods)


class HttpResponseNotAcceptable(HttpResponse):
    """406 Not Acceptable.

    Use when you can't return a format the client will accept (Accept
    header). Problem is *response* format, not the request body (that's 415).

    Example::

        return HttpResponseNotAcceptable("Only application/json is available")
    """

    status_code = 406


class HttpResponseProxyAuthenticationRequired(HttpResponse):
    """407 Proxy Authentication Required.

    Like 401 but for proxy auth. Set Proxy-Authenticate; client retries
    with Proxy-Authorization.

    Example::

        response = HttpResponseProxyAuthenticationRequired()
        response["Proxy-Authenticate"] = 'Basic realm="Proxy"'
        return response
    """

    status_code = 407


class HttpResponseRequestTimeout(HttpResponse):
    """408 Request Timeout.

    Use when the client took too long to send the request (e.g. body
    never arrived). Client can retry. Optionally pass ``retry_after``
    (seconds or datetime) to set Retry-After.

    Args:
        retry_after: Optional. Seconds (int/float) or a datetime (UTC if
            naive). Sets the Retry-After header.

    Example::

        return HttpResponseRequestTimeout(retry_after=60)
    """

    status_code = 408

    def __init__(
        self,
        retry_after: int | float | datetime | None = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        if retry_after is not None:
            self["Retry-After"] = retry_after_value(retry_after)


class HttpResponseConflict(HttpResponse):
    """409 Conflict.

    Use when the request conflicts with current state (e.g. concurrent
    edit, version mismatch). Include enough info so the client can retry.

    Example::

        return HttpResponseConflict("Resource was modified by another user")
    """

    status_code = 409


class HttpResponseGone(_HttpResponseGone):
    """410 Gone.

    Use when the resource used to exist but is permanently gone (e.g.
    removed page). Tells clients to drop links. Use 404 if you're not sure.

    Example::

        return HttpResponseGone()
    """

    pass


class HttpResponseLengthRequired(HttpResponse):
    """411 Length Required.

    Use when the request body must include a Content-Length header and
    didn't. Client can retry with the header.
    Typically this will be implemented by the server, or maybe it's in some specialist middleware.

    Example::

        return HttpResponseLengthRequired()
    """

    status_code = 411


class HttpResponsePreconditionFailed(HttpResponse):
    """412 Precondition Failed.

    Use when a conditional header (If-Match, If-None-Match,
    If-Unmodified-Since) didn't match the current resource state.
    Typically, this will only be implemented in some specialist middleware.

    Example::

        return HttpResponsePreconditionFailed()
    """

    status_code = 412


class HttpResponseContentTooLarge(HttpResponse):
    """413 Content Too Large.

    Use when the request body is too big. Optionally pass ``retry_after``
    (seconds or datetime) when the condition might be temporary.

    Args:
        retry_after: Optional. Seconds (int/float) or a datetime (UTC if
            naive). Sets the Retry-After header.

    Example::

        return HttpResponseContentTooLarge(retry_after=300)
    """

    status_code = 413

    def __init__(
        self,
        retry_after: int | float | datetime | None = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        if retry_after is not None:
            self["Retry-After"] = retry_after_value(retry_after)


class HttpResponseUriTooLong(HttpResponse):
    """414 URI Too Long.

    Use when the URL is too long. In practice the web server often
    enforces this before Django.

    Example::

        return HttpResponseUriTooLong()
    """

    status_code = 414


class HttpResponseUnsupportedMediaType(HttpResponse):
    """415 Unsupported Media Type.

    Use when the request body is in a format you don't support
    (Content-Type or content). That's *request* body; for response
    format the client accepts, use 406.

    Example::

        return HttpResponseUnsupportedMediaType()
    """

    status_code = 415


class HttpResponseRangeNotSatisfiable(HttpResponse):
    """416 Range Not Satisfiable.

    Use when the Range header can't be satisfied. Pass ``total_length``
    to set Content-Range (e.g. ``bytes */47022``). For non-byte range
    units, set Content-Range manually.

    Args:
        total_length: Optional. Full length of the selected representation
            in bytes. Sets ``Content-Range: bytes */<total_length>``.

    Example::

        return HttpResponseRangeNotSatisfiable(total_length=resource_size)
    """

    status_code = 416

    def __init__(
        self,
        total_length: int | None = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        if total_length is not None:
            self["Content-Range"] = f"bytes */{total_length}"


class HttpResponseExpectationFailed(HttpResponse):
    """417 Expectation Failed.

    Use when you can't satisfy the request's Expect header (e.g.
    Expect: 100-continue but you won't accept the body).

    Example::

        return HttpResponseExpectationFailed()
    """

    status_code = 417


class HttpResponseMisdirectedRequest(HttpResponse):
    """421 Misdirected Request.

    Use when this server isn't the right one for the request (e.g. wrong
    host for the URI). Client should try another connection. Proxies
    shouldn't send this.

    Example::

        return HttpResponseMisdirectedRequest()
    """

    status_code = 421


class HttpResponseUnprocessableContent(HttpResponse):
    """422 Unprocessable Content.

    Use when the request body is valid (not 415) but you can't process it
    (e.g. validation failed, semantic error). Common in REST APIs to
    separate from 400 syntax errors.

    Example::

        return HttpResponseUnprocessableContent(
            json.dumps({"errors": validation_errors}),
            content_type="application/json",
        )
    """

    status_code = 422


class HttpResponseUpgradeRequired(HttpResponse):
    """426 Upgrade Required.

    Use when the client must upgrade (e.g. to TLS). Pass ``upgrade``
    with the required protocol(s); this sets Upgrade and Connection:
    Upgrade. You will typically not see this in Django views.

    Args:
        upgrade: Protocol name(s), e.g. ``"TLS/1.2"`` or
            ``["HTTP/3.0", "websocket"]``. Sets Upgrade and Connection headers.

    Example::

        return HttpResponseUpgradeRequired(upgrade="TLS/1.2")
    """

    status_code = 426

    def __init__(
        self,
        upgrade: str | Iterable[str] | None = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        if upgrade is not None:
            if isinstance(upgrade, str):
                upgrade = [upgrade]
            self["Upgrade"] = ", ".join(upgrade)
            self["Connection"] = "Upgrade"


# ---------------------------------------------------------------------------
# 5xx Server Error
# ---------------------------------------------------------------------------


class HttpResponseInternalServerError(_HttpResponseServerError):
    """500 Internal Server Error.

    Use for unexpected server errors. Often sent automatically when your
    view raises; you can also return it explicitly for custom error pages.
    """

    pass


class HttpResponseNotImplemented(HttpResponse):
    """501 Not Implemented.

    Use when the server doesn't support this at all (e.g. unknown method).
    For a known method that's not allowed on this resource, use 405.
    Often sent by the web server; in Django you'll usually use 405.
    """

    status_code = 501


class HttpResponseBadGateway(HttpResponse):
    """502 Bad Gateway.

    Use when you're a gateway/proxy and the upstream server returned
    invalid or no response. Usually sent by the reverse proxy, not Django.
    """

    status_code = 502


class HttpResponseServiceUnavailable(HttpResponse):
    """503 Service Unavailable.

    Use when you're temporarily unable to handle the request (overload,
    maintenance). Optionally pass ``retry_after`` (seconds or a datetime)
    and this class sets the Retry-After header.

    Args:
        retry_after: Optional. Seconds (int/float) or a datetime (UTC if
            naive). Sets the Retry-After header.

    Example::

        return HttpResponseServiceUnavailable(retry_after=120)
    """

    status_code = 503

    def __init__(
        self,
        retry_after: int | float | datetime | None = None,
        *args: Any,
        **kwargs: Any,
    ) -> None:
        super().__init__(*args, **kwargs)
        if retry_after is not None:
            self["Retry-After"] = retry_after_value(retry_after)


class HttpResponseGatewayTimeout(HttpResponse):
    """504 Gateway Timeout.

    Use when you're a gateway/proxy and the upstream didn't respond in
    time. Usually sent by the reverse proxy, not Django.
    """

    status_code = 504


class HttpResponseHttpVersionNotSupported(HttpResponse):
    """505 HTTP Version Not Supported.

    Use when the request's HTTP version isn't supported. Usually handled
    by the web server, not Django.
    """

    status_code = 505


# Public API: all response classes in status-code order, plus helpers
__all__ = [
    "HttpResponse",  # base; default 200 when used directly
    "retry_after_value",
    "set_content_location",
    "HttpResponseContinue",
    "HttpResponseSwitchingProtocols",
    "HttpResponseOK",
    "HttpResponseCreated",
    "HttpResponseAccepted",
    "HttpResponseNonAuthoritativeInformation",
    "HttpResponseNoContent",
    "HttpResponseResetContent",
    "HttpResponsePartialContent",
    "HttpResponseMultipleChoices",
    "HttpResponseMovedPermanently",
    "HttpResponseFound",
    "HttpResponseSeeOther",
    "HttpResponseNotModified",
    "HttpResponseUseProxy",
    "HttpResponseTemporaryRedirect",
    "HttpResponsePermanentRedirect",
    "HttpResponseBadRequest",
    "HttpResponseUnauthorized",
    "HttpResponsePaymentRequired",
    "HttpResponseForbidden",
    "HttpResponseNotFound",
    "HttpResponseNotAllowed",
    "HttpResponseNotAcceptable",
    "HttpResponseProxyAuthenticationRequired",
    "HttpResponseRequestTimeout",
    "HttpResponseConflict",
    "HttpResponseGone",
    "HttpResponseLengthRequired",
    "HttpResponsePreconditionFailed",
    "HttpResponseContentTooLarge",
    "HttpResponseUriTooLong",
    "HttpResponseUnsupportedMediaType",
    "HttpResponseRangeNotSatisfiable",
    "HttpResponseExpectationFailed",
    "HttpResponseMisdirectedRequest",
    "HttpResponseUnprocessableContent",
    "HttpResponseUpgradeRequired",
    "HttpResponseInternalServerError",
    "HttpResponseNotImplemented",
    "HttpResponseBadGateway",
    "HttpResponseServiceUnavailable",
    "HttpResponseGatewayTimeout",
    "HttpResponseHttpVersionNotSupported",
]
