from sanic import Blueprint, Request, HTTPResponse, response
from sanic.models.handler_types import RouteHandler
from functools import wraps
from inspect import isawaitable
from typing import Callable, Dict, Any, Union, Awaitable, List, Optional

ACCEPTED_WISH_VERS = ['wish.alpha.v1']

WishHandler = Callable[..., Union[Dict[str, Any], Awaitable[Dict[str, Any]]]]

def wish_endpoint(bp: Blueprint, uri: str, *, methods: Optional[List[str]] = None) -> Callable[[WishHandler], RouteHandler]:
    if methods is None:
        methods = ['POST']

    def decorator(fn: WishHandler) -> RouteHandler:
        @wraps(fn)
        async def wrapped(req: Request, *args: Any, **kwargs: Any) -> HTTPResponse:
            v = req.headers.get('X-Wish-Version', '(none)')
            if v not in ACCEPTED_WISH_VERS:
                return response.json({
                    'error': 'WISH_VERSION_MISMATCH',
                    'error_msg': f'前端版本 {v} 不是最新',
                })

            retval_ = fn(req, *args, **kwargs)
            retval = (await retval_) if isawaitable(retval_) else retval_

            return response.json({
                'error': None, # may be overridden by retval
                **retval,
            })

        return bp.route(uri, methods)(wrapped) # type: ignore

    return decorator
[((16, 9, 16, 18), 'functools.wraps', 'wraps', ({(16, 15, 16, 17): 'fn'}, {}), '(fn)', False, 'from functools import wraps\n'), ((28, 19, 31, 14), 'sanic.response.json', 'response.json', ({(28, 33, 31, 13): "{'error': None, **retval}"}, {}), "({'error': None, **retval})", False, 'from sanic import Blueprint, Request, HTTPResponse, response\n'), ((20, 23, 23, 18), 'sanic.response.json', 'response.json', ({(20, 37, 23, 17): "{'error': 'WISH_VERSION_MISMATCH', 'error_msg': f'前端版本 {v} 不是最新'}"}, {}), "({'error': 'WISH_VERSION_MISMATCH', 'error_msg': f'前端版本 {v} 不是最新'}\n    )", False, 'from sanic import Blueprint, Request, HTTPResponse, response\n'), ((26, 40, 26, 60), 'inspect.isawaitable', 'isawaitable', ({(26, 52, 26, 59): 'retval_'}, {}), '(retval_)', False, 'from inspect import isawaitable\n')]