import random
import re
import json
from sanic import response
from unify_api.utils.response_code import RET
from pot_libs.settings import SETTING
from pot_libs.sanic_api import summary
from pot_libs.utils.pendulum_wrapper import my_pendulum
from unify_api.constants import PRODUCT_INFOS
from unify_api.modules.users.components.current_user_info_cps import *
from pot_libs.common.components.responses import success_res
from unify_api.modules.users.procedures.jwt_user import jwt_user
from unify_api.modules.users.procedures.send_sms import sample
from pot_libs.aredis_util import aredis_utils
from unify_api.modules.users.dao.current_user_info_dao import *
from unify_api.modules.common.dao.common_dao import user_by_phone_number, \
    user_by_user_id
from pot_libs.aiohttp_util.aiohttp_utils import AioHttpUtils
from unify_api.modules.users.procedures.jwt_user import auth_phone_verify, \
    check_password

AUTH_EXP = 300  # redis缓存时间
VALIDATION_EXP = 60   # 发送验证码间隔时间


@summary('用户头像昵称等信息')
async def get_user_info(request) -> UserInfoResponse:
    # 1.从jwt中获取user_id
    user_id = jwt_user(request)
    if not user_id:
        valid_body = {
            "code": 401,
            "message": "token is valid",
            "data": {},
            "srv_time": my_pendulum.now().to_datetime_string()
        }
        return response.json(body=valid_body, status=401)
    # 2.查询用户
    user_info = await user_by_user_id(user_id)
    if not user_info:
        return UserInfoResponse().user_error()
    # head_image_url = ""
    # 3.查询出用户昵称等信息
    # if user_info["wechat_id"]:
    #     sql = "select nickname, headimgurl, user.zhiweiu_auth, " \
    #           "user.real_name, user.unit from wechat_mp_user wu " \
    #           "inner join user on " \
    #           "wu.unionid = user.wechat_id where user.user_id = %s"
    #     async with MysqlUtil() as conn:
    #         user_info = await conn.fetchone(sql=sql, args=(int(user_id)), )
    #     head_image_url = user_info.get("headimgurl")[5:]
    # 4. 查询用户产品信息
    pro_sql = "select product from user_product_auth where user_id = %s"
    async with MysqlUtil() as conn:
        pro_info = await conn.fetchall(sql=pro_sql, args=(int(user_id)), )
    # [{'product': 1}, {'product': 2}, {'product': 3}]
    product_list = []
    if pro_info:
        for pro in pro_info:
            # ulock的app产品跳过, PRODUCT_INFOS只存u+云的产品
            if pro["product"] not in PRODUCT_INFOS:
                continue
            product_list.append(PRODUCT_INFOS[pro["product"]])
        product_list = sorted(product_list, key=lambda x: x["sort_num"])
    # 4. 查询zhiweiu权限, 默认普通用户
    zhiweiu_auth = user_info.get("zhiweiu_auth")
    if not zhiweiu_auth and zhiweiu_auth != 0:
        zhiweiu_auth = 1
    return UserInfoResponse(
        user_id=user_id,
        # nick_name=user_info.get("nickname") or user_info.get("real_name"),
        nick_name=user_info.get("real_name"),
        head_image_url="http://cdn.ucyber.cn/common/default-avatar.png",
        real_name=user_info.get("real_name"),
        unit=user_info.get("unit"),
        product_list=product_list,
        zhiweiu_auth=zhiweiu_auth
    )


@summary("发送手机验证码")
async def get_send_sms(request):
    phone = request.args.get("phone")
    if re.match(r'^1[3-9]\d{9}$', phone):
        send_flag = await aredis_utils.RedisUtils().get(
            f"sms:send_sms_flag_{phone}")
        if send_flag:
            return success_res(code=RET.send_sms_quick, msg="请求验证码过于频繁")
        code = '%06d' % random.randint(1, 999999)
        # 短信间隔
        await aredis_utils.RedisUtils().setex(
            f"sms:send_sms_flag_{phone}", VALIDATION_EXP, 1)
        await aredis_utils.RedisUtils().setex(
            f"sms:sms_{phone}", AUTH_EXP, code)
        result_body = sample.main([phone, code])
        log.info(f"send_sms {phone}, {code}, {result_body}")
        if result_body.code == "OK":
            return success_res(msg="发送成功")
        else:
            if result_body.message == "触发天级流控Permits:10":
                msg = "您今日发送短信次数已用完"
            elif result_body.message == "触发小时级流控Permits:5":
                msg = "请求验证码过于频繁，请1小时后重新发送"
            elif result_body.message == "触发分钟级流控Permits:1":
                msg = "请求验证码过于频繁，请1分钟后重新发送"
            else:
                msg = "验证码发送失败"
            return success_res(code=RET.send_sms_quick2, msg=msg)
    return success_res(code=RET.send_sms_fail, msg="手机号码不合法")


@summary("首次登录保存用户信息")
async def post_save_userinfo(request, body: SaveUserReq):
    real_name = body.real_name
    unit = body.unit
    job = body.job
    phone = body.phone
    password = body.password
    password2 = body.password2
    wechat_id = body.wechat_id
    verify = body.verify
    if not all([real_name, job, unit, phone, password]):
        return success_res(code=RET.params_loss, msg="缺少必传参数")
    if password != password2:
        return success_res(code=RET.password_error, msg="两次密码不一致")
    passwd = check_password(password)
    if verify:
        auth_verify = await auth_phone_verify(phone, verify)
        if not auth_verify:
            return success_res(code=RET.verify_error, msg="验证码不一致")
    if wechat_id:
        wechat_info = await is_having_wechat_id(wechat_id)
        is_having = await phone_is_having_dao(phone)
        if wechat_info:
            await update_user_info_by_wechat_id(real_name, unit, job, passwd,
                                                phone, wechat_id)
        elif is_having and is_having["wechat_id"]:
            return success_res(code=RET.verify_error, msg="该手机号已注册")
        elif is_having:
            # 修改信息
            await update_user_info(real_name, unit, job, passwd, phone,
                                   wechat_id)
        else:
            # 注册
            await insert_user_info(real_name, unit, job, passwd, phone,
                                   wechat_id)
    else:
        await insert_user_info(real_name, unit, job, passwd, phone)
    user = await user_by_phone_number(phone)
    # 获取token
    request_body = {
        "phone": phone,
        "client_name": "validation",
        "host": request.host,
        "user_id": user["user_id"],
        "db": SETTING.mysql_db
    }
    resp_str, status = await AioHttpUtils().post(
        SETTING.auth_url,
        request_body,
        timeout=50,
    )
    log.info(f"post_save_userinfo resp_str={resp_str} status={status}")
    resp = json.loads(resp_str)
    if status == 200:
        return success_res(data=resp)
    else:
        return success_res(msg="保存用户信息成功")


@summary("修改手机号")
async def post_update_phone(request, body: UpdatePhoneReq):
    user_id = body.user_id
    phone = body.phone
    verify = body.verify
    log.info(f"post_update_phone {phone} {verify}")
    # 检验手机号
    wechat_product_dict, old_zhiwei_u, old_role = {}, None, None
    wechat_product_auth, wechat_product_auth_dict = None, {}
    phone_info = await user_by_phone_number(phone)
    if phone_info:
        if phone_info.get("wechat_id"):
            return 401, {"code": 40001, "data": None, "message": "该手机号已被绑定"}
        else:
            # 删除这条记录
            await update_not_wechat(user_id, phone)
        old_zhiwei_u = phone_info["zhiweiu_auth"]
        old_role = phone_info["role"]
        wechat_product_auth = await \
            search_user_product_auth_dao(phone_info["user_id"])
        wechat_product_auth_dict = \
            {wechat_product["product"]: wechat_product["cid_ext"]
             for wechat_product in wechat_product_auth} \
                if wechat_product_auth else {}
        wechat_product_dict = \
            {wechat_product["product"]: wechat_product["proxy"]
             for wechat_product in wechat_product_auth} \
                if wechat_product_auth else {}
    # 效验验证码
    auth_verify = await auth_phone_verify(phone, verify)
    if not auth_verify:
        return success_res(code=RET.verify_error, msg="验证码不一致")

    user_product_auth = await search_user_product_auth_dao(user_id)
    user_product_auth_dict = \
        {user_product["product"]: user_product["cid_ext"]
         for user_product in user_product_auth} if user_product_auth else {}
    user_product_dict = \
        {user_product["product"]: user_product["proxy"]
         for user_product in user_product_auth} if user_product_auth else {}
    if all([wechat_product_auth, user_product_auth]):
        product_auth = wechat_product_auth_dict.update(
            user_product_auth_dict)
    elif wechat_product_auth:
        product_auth = wechat_product_auth_dict
    elif user_product_auth:
        product_auth = user_product_auth_dict
    else:
        product_auth = None
    # 绑定手机和智维u、role
    sql_list = [f"phone_number='{phone}'"]
    if old_zhiwei_u:
        sql_list.append(f"zhiweiu_auth={old_zhiwei_u}")
    if old_role:
        sql_list.append(f"role={old_role}")
    mid_sql = ",".join(sql_list)
    await update_user_auth_dao(user_id, mid_sql)

    # 修改权限
    if product_auth:
        for key, value in product_auth.items():
            is_auth = await search_product_auth_dao(user_id, key)
            if is_auth:
                await update_product_auth_dao(key, value, user_id,
                                              proxy=user_product_dict.get(key) or wechat_product_dict.get(key))
            else:
                await insert_product_auth_dao(user_id, key, value,
                                              proxy=(user_product_dict.get(key) or wechat_product_dict.get(key)))
    return success_res(msg="修改成功")


@summary("验证手机号")
async def post_auth_phone(request, body: AuthPhoneReq):
    phone = body.phone
    verify = body.verify
    auth_verify = await auth_phone_verify(phone, verify)
    if not auth_verify:
        return success_res(code=RET.verify_error, msg="验证码不一致")
    return success_res(msg="验证通过")


@summary("找回密码")
async def post_back_password(request, body: PhoneIsHavingReq):
    phone = body.phone
    is_delete = await phone_is_having_dao(phone)
    if not is_delete:
        return success_res(code=RET.phone_not_register, msg="手机号未注册或已注销")
    return success_res(msg="成功")


@summary("修改密码")
async def post_update_password(request, body: UpdatePasswordReq):
    phone = body.phone
    is_delete = await phone_is_having_dao(phone)
    if not is_delete:
        return success_res(code=RET.phone_not_register, msg="手机号未注册")
    password = body.password
    password2 = body.password2
    if password != password2:
        return success_res(code=RET.password_error, msg="两次密码不一致")
    passwd = check_password(password)
    await update_password_dao(phone, passwd)
    return success_res(msg="修改成功")


@summary("获取个人信息")
async def post_userinfo(request, body: UserinfoReq) -> UserinfoResp:
    user_id = body.user_id
    data = await user_by_user_id(user_id)
    is_wechat = 1 if data["wechat_id"] else 0
    return UserinfoResp(user_id=data["user_id"], phone=data["phone_number"],
                        unit=data.get("unit") or "", job=data.get("job") or "",
                        name=data.get("real_name") or "", is_wechat=is_wechat)


@summary("修改个人信息")
async def post_update_userinfo(request, body: UpdateUserInfoReq) \
        -> UserinfoResp:
    user_id = body.user_id
    name = body.name
    unit = body.unit
    job = body.job
    if not any([name, unit, job]):
        return success_res(code=RET.params_loss, msg="缺少参数")
    if name:
        await update_userinfo_dao(user_id, 'real_name', name)
    elif unit:
        await update_userinfo_dao(user_id, 'unit', unit)
    else:
        await update_userinfo_dao(user_id, 'job', job)
    data = await user_by_user_id(user_id)
    is_wechat = 1 if data["wechat_id"] else 0
    return UserinfoResp(user_id=data["user_id"], phone=data["phone_number"],
                        unit=data["unit"], job=data["job"],
                        name=data["real_name"], is_wechat=is_wechat)


@summary("解除微信绑定")
async def post_delete_wechat(request, body: UserinfoReq) \
        -> UserinfoResp:
    user_id = body.user_id
    await update_userinfo_dao(user_id, "wechat_id", None)
    return success_res(msg="解除微信绑定成功")


@summary("微信绑定")
async def post_update_wechat(request, body: UpdateWechatReq):
    user_id = body.user_id
    code = body.code
    # 1.通过code换取网页授权access_token
    url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&" \
          "secret=%s&code=%s&grant_type=authorization_code" % \
          (SETTING.wechat_open_appid2, SETTING.wechat_open_secret_key2, code)
    log.info(f"post_update_wechat url:{url}")
    res_token, token_status = await AioHttpUtils().get(url)
    log.info(f"post_update_wechat res_token:{res_token}")
    if token_status != 200:
        log.error("post_update_wechat get access_token fail")
        return success_res(code=RET.wechat_error, msg="微信绑定失败")
    result = json.loads(res_token)
    # 2.获取用户信息
    if 'access_token' not in result:
        log.error("post_update_wechat access_token not found")
        return success_res(code=RET.wechat_error, msg="微信绑定失败")
    url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s" \
          % (result['access_token'], result['openid'])
    res, user_info_status = await AioHttpUtils().get(url)
    log.info(f"post_update_wechat user_info:{res}")
    if user_info_status != 200:
        log.error("post_update_wechat get user info fail")
        return success_res(code=RET.wechat_error, msg="微信绑定失败")
    user_info = json.loads(res)
    wechat_product_dict, old_zhiwei_u, old_role = {}, None, None
    if 'openid' in user_info and 'unionid' in user_info:
        unionid = user_info['unionid']
        data = await search_user_by_wechat_id_dao(unionid)
        wechat_product_auth, wechat_product_auth_dict = None, {}
        log.info(f"post_update_wechat{data}, unionid:{unionid}")
        if data:
            log.info(f"post_update_wechat{data}")
            if data.get("phone_number"):
                return success_res(code=RET.wechat_repeat,
                                   msg="该微信号已经被绑定")
            else:
                old_zhiwei_u = data["zhiweiu_auth"]
                old_role = data["role"]
                r = '%04d' % random.randint(1, 9999)
                new_wechat_id = f"delete{r}{unionid}"
                # 删除老用户
                await update_user_is_delete(data["user_id"], new_wechat_id)
                # # 添加微信到新用户
                # await update_not_phone(user_id, unionid)
                # 修改权限
                wechat_product_auth = await \
                    search_user_product_auth_dao(data["user_id"])
                wechat_product_auth_dict = \
                    {wechat_product["product"]: wechat_product["cid_ext"]
                     for wechat_product in wechat_product_auth} \
                        if wechat_product_auth else {}
                wechat_product_dict = \
                    {wechat_product["product"]: wechat_product["proxy"]
                     for wechat_product in wechat_product_auth} \
                        if wechat_product_auth else {}
        user_product_auth = await search_user_product_auth_dao(user_id)
        user_product_auth_dict = \
            {user_product["product"]: user_product["cid_ext"]
             for user_product in user_product_auth} \
                if user_product_auth else {}
        user_product_dict = \
            {user_product["product"]: user_product["proxy"]
             for user_product in user_product_auth} \
                if user_product_auth else {}
        if all([wechat_product_auth, user_product_auth]):
            product_auth = wechat_product_auth_dict.update(
                user_product_auth_dict)
        elif wechat_product_auth:
            product_auth = wechat_product_auth_dict
        elif user_product_auth:
            product_auth = user_product_auth_dict
        else:
            product_auth = None
        # 绑定微信和智维u、role
        sql_list = [f"wechat_id='{unionid}'"]
        if old_zhiwei_u:
            sql_list.append(f"zhiweiu_auth={old_zhiwei_u}")
        if old_role:
            sql_list.append(f"role={old_role}")
        mid_sql = ",".join(sql_list)
        await update_user_auth_dao(user_id, mid_sql)
        # 修改权限
        if product_auth:
            for key, value in product_auth.items():
                is_auth = await search_product_auth_dao(user_id, key)
                if is_auth:
                    await update_product_auth_dao(key, value, user_id,
                                                  proxy=user_product_dict.get(key) or wechat_product_dict.get(key))
                else:
                    await insert_product_auth_dao(user_id, key, value,
                                                  proxy=user_product_dict.get(key) or wechat_product_dict.get(key))
        log.info(f"post_update_wechat product_auth:{product_auth}")
        return success_res(msg="微信绑定成功")
    return success_res(code=RET.wechat_error, msg="微信绑定失败")


@summary("手机号码是否被绑定")
async def post_phone_is_having(request, body: PhoneIsHavingReq):
    phone = body.phone
    data = await phone_is_having_dao(phone)
    if data:
        return success_res(code=RET.phone_repeat, msg="该手机号码已经被绑定")
    return success_res(msg="该手机号码可用")


@summary("注销用户")
async def post_delete_user(request, body: UserinfoReq):
    user_id = body.user_id
    data = await user_by_user_id(user_id)
    code = '%04d' % random.randint(1, 9999)
    new_wechat_id = f"delete{code}" + data["wechat_id"] \
        if data["wechat_id"] else None
    await update_user_is_delete(user_id, new_wechat_id)
    return success_res(msg="注销成功")
