# Generated by smithplates HTTP codegen. Do not edit.

from __future__ import annotations

from fastapi.responses import JSONResponse, RedirectResponse, Response
from generated.asset_api.asset_api.operation_bindings import OperationHttpBinding
from pydantic import BaseModel


def dispatch_api_response(
    response: BaseModel | None,
    binding: OperationHttpBinding,
) -> Response | RedirectResponse | JSONResponse | BaseModel | None:
    """Map a service-layer response model to HTTP using OpenAPI-derived bindings."""
    variant = binding.variant_for(response)
    return _to_http_response(response, variant=variant)


def _to_http_response(
    response: BaseModel | None,
    *,
    variant: object,
) -> Response | RedirectResponse | JSONResponse | BaseModel | None:
    from generated.asset_api.asset_api.operation_bindings import ResponseVariantBinding

    if not isinstance(variant, ResponseVariantBinding):
        msg = "Expected ResponseVariantBinding"
        raise TypeError(msg)

    headers, media_type = _response_headers_and_media_type(response, variant)

    if response is None:
        return Response(status_code=variant.status_code)

    has_body = media_type is not None
    if not has_body:
        if _is_redirect_status(variant.status_code) and "Location" in headers:
            return RedirectResponse(url=headers["Location"], status_code=variant.status_code)
        if headers:
            return Response(status_code=variant.status_code, headers=headers)
        return Response(status_code=variant.status_code)

    exclude_fields = {field_name for field_name, _ in variant.header_bindings}
    body_content = response.model_dump(mode="json", exclude_none=True, exclude=exclude_fields)

    if headers:
        return JSONResponse(
            status_code=variant.status_code,
            content=body_content,
            media_type=media_type,
            headers=headers,
        )

    if variant.status_code == 200 and variant.header_bindings == () and variant.static_headers == ():
        return response

    return JSONResponse(
        status_code=variant.status_code,
        content=body_content,
        media_type=media_type,
    )


def _response_headers_and_media_type(
    response: BaseModel | None,
    variant: object,
) -> tuple[dict[str, str], str | None]:
    from generated.asset_api.asset_api.operation_bindings import ResponseVariantBinding

    if not isinstance(variant, ResponseVariantBinding):
        msg = "Expected ResponseVariantBinding"
        raise TypeError(msg)

    headers = {name: value for name, value in variant.static_headers}
    if response is not None:
        for member_name, header_name in variant.header_bindings:
            headers[header_name] = str(getattr(response, member_name))

    media_type = headers.pop("Content-Type", variant.media_type)
    return headers, media_type


def _is_redirect_status(status_code: int) -> bool:
    return status_code in {301, 302, 303, 307, 308}
