# -*- coding:utf-8 -*-
import re
from functools import wraps
from sanic.response import json
import ujson
from pot_libs.aiohttp_util.aiohttp_utils import AioHttpUtils
from pot_libs.settings import SETTING
from pot_libs.utils.pendulum_wrapper import my_pendulum
from unify_api.constants import PRODUCT
from unify_api.modules.common.procedures.cids import get_cids, get_proxy_cids
from pot_libs.logger import log
from sanic import response
import json
from unify_api.modules.users.procedures import user_product_auth


def authorized():
    def decorator(f):
        @wraps(f)
        async def decorated_function(request, *args, **kwargs):
            # run some method that checks the request
            # for the client's authorization status
            is_authorized = await user_product_auth.check_user_auth(request)

            if is_authorized:
                # the user is authorized.
                # run the handler method and return the response
                response = await f(request, *args, **kwargs)
                return response
            else:
                # the user is not authorized.
                return json({'status': 'not_authorized'}, 403)

        return decorated_function

    return decorator


@authorized()
async def get_test(request):
    return json({'status': 'authorized'})


def is_need_verify(path):
    if SETTING.debug_mode == 1:
        return False
    if "swagger" in path:
        return False

    log.info("is_or_not_need_verify path:%s", path)
    if "swagger" in path:
        return False

    if re.match("^/unify-api/auth/?$", path):
        log.info("auth not need verify")
        return False

    if re.match("^/unify-api/upgrade/?", path):
        log.info("upgrade device not need verify")
        return False

    if re.match("^/unify-api/uassistant/?", path):
        log.info("uassistant not need verify")
        return False

    if re.match("^/unify-api/device-cloud/?", path):
        log.info("device_cloud not need verify")
        return False

    if re.match("^/unify-api/users/current-user-info/send-sms?", path):
        log.info("send-sms not need verify")
        return False

    if re.match("^/unify-api/users/current-user-info/save-userinfo?", path):
        log.info("save-userinfo not need verify")
        return False

    if re.match("^/unify-api/users/current-user-info/auth-phone?", path):
        log.info("auth-phone not need verify")
        return False

    if re.match("^/unify-api/users/current-user-info/back-password?", path):
        log.info("back-password not need verify")
        return False

    if re.match("^/unify-api/users/current-user-info/update-password?", path):
        log.info("update-password not need verify")
        return False

    if re.match("^/api/common/wechat/mp", path):
        log.info("/api/common/wechat/mp not need verify")
        return False

    if re.search("/qk-website", path):
        log.info(f"{path} not need verify")
        return False

    # if re.search("/qkadmin", path):
    #     log.info(f"{path} not need verify")
    #     return False
    
    # if re.match("^/unify-api/users/logout/user-logout/?$", path):
    #     log.info("logout not need verify")
    #     return False

    return True


async def auth_verify(request):
    if SETTING.debug_mode == 1:
        return False
    path = request.path
    if is_need_verify(path):
        token = request.token
        # token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMDA4NiwiZXhwIjoxNjM3NTUyOTQwfQ.i-ACln1j48WM0ZuFyMhCq5DPITEiywCRr4VZaWHDH84"
        if not token:
            token = request.args.get("token")
            if token and token.startswith("B"):
                token = token[7:]
        log.info("auth_verify, token:%s", token)
        # token失效返回的body
        valid_body = {
            "code": 401,
            "message": "token is valid",
            "data": {},
            "srv_time": my_pendulum.now().to_datetime_string()
        }
        if token is None:
            return response.json(body=valid_body, status=401)
        # 直接将请求转发到auth
        resp_str, status = await AioHttpUtils().post(
            SETTING.verify_url,
            data={"db": SETTING.mysql_db},
            timeout=50,
            headers={"Authorization": f"Bearer {token}"}
        )
        log.info(
            f"request auth_url resp_str={resp_str} {type(resp_str)} status={status}")
        if status == 200:
            payload = ujson.loads(resp_str)
            setattr(request.ctx, "user_id", payload["user_id"])
        else:
            # 除了200响应其他都认为失败
            return response.json(body=valid_body, status=401)
    else:
        log.info("not need verify, path:%s", path)


def is_need_auth_verify_cid(path):
    if SETTING.debug_mode == 1:
        return False
    if "swagger" in path:
        return False
    if re.match("^/unify-api/auth/", path):
        return False
    if re.match("^/api/common/wechat/mp", path):
        return False
    if re.search("/qk-website", path):
        log.info(f"{path} not need verify")
        return False
    if re.search("/qkadmin", path):
        log.info(f"{path} not need verify")
        return False
    return True


async def auth_verify_cid(request):
    """增加工厂权限校验"""
    if SETTING.debug_mode == 1:
        return False
    path = request.path
    # if not re.match("^/unify-api/auth/?$", path):
    if is_need_auth_verify_cid(path):
        # 1.获取参数
        host = request.host
        # host = "zhiDianU"
        product = PRODUCT.get(host)
        log.info(f"host：{host} product:{product}")
        # 智维u, 直接返回
        if product in [10, 13]:
            return

        cid, cids, cid_list = None, None, None
        # 2. 如果参数传了产品类型, 根据参数获取, 后续修改不再根据host取product
        args = request.json
        log.info(f"auth_verify_cid {args}")
        if args:
            cid = args.get("cid")
            cids = args.get("cids")
            cid_list = args.get("cids")
            if args.get("product"):
                product = args.get("product")
        # 验证失败返回的body
        fail_body = {
            "code": 401,
            "message": "cid verify fail",
            "data": {},
            "srv_time": my_pendulum.now().to_datetime_string()
        }
        # 3. 如果参数中包含cid或者cids,cid_list
        if cid or cids or cid_list:
            user_id = request.ctx.user_id

            proxy_id = args.get("proxy_id")
            # 2.2 从mysql获取
            if proxy_id:
                cid_res_list = await get_proxy_cids(user_id, product, proxy_id)
            else:
                cid_res_list = await get_cids(user_id, product)
            # 2.1 先从redis取cid_list
            # cid_info = await get_product_auth(user_id, product)
            # if cid_info:
            #     cid_res_list = [int(cid) for cid in cid_info.get("product")]
            # else:

            # cid_res_list = await get_cids(user_id, product)
            # 2.3 参数中的cid_args
            cid_args = None
            if cid:
                cid_args = [cid]
            if cids:
                cid_args = cids
            if cid_list:
                cid_args = cid_list
            log.info(f"{user_id} cid_args:{cid_args}")
            log.info(f"{user_id} cid_res_list:{cid_res_list}")
            if not (set(cid_args) <= set(cid_res_list)):
                return response.json(body=fail_body, status=401)
    log.info("cid verify pass")
