import inspect
from collections import namedtuple
from datetime import datetime
from functools import wraps
from typing import Callable, TypeVar

import pytz
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse

from app.settings import settings

__all__ = ['HttpCode', 'HttpResp', 'unified_resp']

RT = TypeVar('RT')  # 返回类型
HttpCode = namedtuple('HttpResp', ['code', 'msg'])


class HttpResp:
    """HTTP响应结果
    """
    SUCCESS = HttpCode(200, '成功')
    FAILED = HttpCode(300, '失败')
    PARAMS_VALID_ERROR = HttpCode(310, '参数校验错误')
    PARAMS_TYPE_ERROR = HttpCode(311, '参数类型错误')
    REQUEST_METHOD_ERROR = HttpCode(312, '请求方法错误')
    ASSERT_ARGUMENT_ERROR = HttpCode(313, '断言参数错误')

    LOGIN_ACCOUNT_ERROR = HttpCode(330, '登录账号或密码错误')
    LOGIN_DISABLE_ERROR = HttpCode(331, '登录账号已被禁用了')
    TOKEN_EMPTY = HttpCode(332, 'token参数为空')
    TOKEN_INVALID = HttpCode(333, 'token参数无效')

    NO_PERMISSION = HttpCode(403, '无相关权限')
    REQUEST_404_ERROR = HttpCode(404, '请求接口不存在')

    SYSTEM_ERROR = HttpCode(500, '系统错误')
    SYSTEM_TIMEOUT_ERROR = HttpCode(504, '请求超时')

# 时区
timezone = pytz.timezone('Asia/Shanghai')

def unified_resp(func: Callable[..., RT]) -> Callable[..., RT]:
    """统一响应格式
        接口正常返回时,统一响应结果格式
    """

    @wraps(func)
    async def wrapper(*args, **kwargs) -> RT:
        if inspect.iscoroutinefunction(func):
            resp = await func(*args, **kwargs) or []
        else:
            resp = func(*args, **kwargs) or []
        return JSONResponse(
            content=jsonable_encoder(
                # 正常请求响应
                {'code': HttpResp.SUCCESS.code, 'msg': HttpResp.SUCCESS.msg, 'data': resp},
                by_alias=False,
                # 自定义日期时间格式编码器
                custom_encoder={
                    datetime: lambda dt: dt.replace(tzinfo=pytz.utc).astimezone(timezone)
                    .strftime(settings.DATETIME_FORMAT)}),
            media_type='application/json;charset=utf-8'
        )

    return wrapper
