"""Middleware to eagerly parse JSON request bodies.

Parses the request body once and caches it in ``request["json_body"]`` so
that downstream middleware (limits, TPM) can read it without re-parsing.
This must be placed in the middleware stack *before* any middleware that
inspects the request body.
"""

from __future__ import annotations

import json
from typing import Awaitable, Callable

from aiohttp import web

Handler = Callable[[web.Request], Awaitable[web.StreamResponse]]
Middleware = Callable[[web.Request, Handler], Awaitable[web.StreamResponse]]


def build_json_body_middleware() -> Middleware:
    """Return middleware that eagerly parses JSON bodies for POST/PUT/PATCH."""

    @web.middleware
    async def json_body_middleware(
        request: web.Request, handler: Handler
    ) -> web.StreamResponse:
        if request.method in {"POST", "PUT", "PATCH"} and request.can_read_body:
            content_type = request.content_type or ""
            if content_type.startswith("application/json"):
                if "json_body" not in request:
                    try:
                        request["json_body"] = await request.json()
                    except json.JSONDecodeError as exc:
                        raise web.HTTPBadRequest(
                            text="invalid json body"
                        ) from exc
        return await handler(request)

    return json_body_middleware
