"""Typed dependency factories for request parsing without signature patching."""

from typing import Annotated, Protocol, cast

from fastapi import Path
from pydantic import BaseModel, TypeAdapter

from auen.types import PKType, PKValue


class ModelBodyParser(Protocol):
    async def __call__(self, obj_in: BaseModel, /) -> BaseModel: ...


class ListBodyParser(Protocol):
    async def __call__(self, items_in: list[BaseModel], /) -> list[BaseModel]: ...


class PathValueParser(Protocol):
    async def __call__(self, pk_value: str, /) -> PKValue: ...


def make_model_body_parser(schema: type[BaseModel]) -> ModelBodyParser:
    """Build a dependency that parses a request body as ``schema``."""
    namespace = {"schema": schema}
    exec(
        "async def _parse(obj_in: schema) -> schema:\n    return obj_in\n",
        namespace,
    )
    return cast(ModelBodyParser, namespace["_parse"])


def make_list_body_parser(schema: type[BaseModel]) -> ListBodyParser:
    """Build a dependency that parses a request body list of ``schema`` items."""
    namespace = {"schema": schema}
    exec(
        "async def _parse(items_in: list[schema]) -> list[schema]:\n"
        "    return items_in\n",
        namespace,
    )
    return cast(ListBodyParser, namespace["_parse"])


def make_path_value_parser(
    *,
    pk_name: str,
    pk_type: PKType,
) -> PathValueParser:
    """Build a dependency that parses the path identifier using alias ``pk_name``."""
    adapter = TypeAdapter(pk_type)

    async def _parse(
        pk_value: Annotated[str, Path(alias=pk_name)],
    ) -> PKValue:
        return adapter.validate_python(pk_value)

    return _parse
