import asyncio
from typing import (
    Awaitable,
    AsyncGenerator,
    Callable,
    Coroutine,
    Dict,
    List,
    Optional,
    Type,
    TypeVar,
    Union,
)
from functools import singledispatch, wraps
import jinja2
from pydantic import BaseModel
from aiofauna.odm import AsyncFaunaModel
from aiohttp.web import Response, json_response
from jinja2 import Template


@singledispatch
def parse_to_response(obj):
    return obj


@parse_to_response.register(BaseModel)
def _(obj):
    return json_response(obj.dict())


@parse_to_response.register(AsyncFaunaModel)
def _(obj):
    return json_response(obj.dict())


@parse_to_response.register(dict)
def _(obj):
    return json_response(obj)


@parse_to_response.register(list)
def _(obj):
    return json_response(obj)


@parse_to_response.register(str)
def _(obj):
    return Response(text=obj, content_type="text/plain")


@parse_to_response.register(jinja2.Template)
def _(obj):
    return Response(text=obj.render(), content_type="text/html")


def return_response(func: Callable) -> Callable:
    @wraps(func)
    async def wrapper(*args, **kwargs) -> Response:
        if asyncio.iscoroutinefunction(func):
            return parse_to_response(await func(*args, **kwargs))
        return parse_to_response(func(*args, **kwargs))

    return wrapper
