# -*- coding:utf-8 -*-
import json
import re
from sanic_jwt import exceptions, Authentication
from pot_libs.aiohttp_util.aiohttp_utils import AioHttpUtils
from pot_libs.aredis_util.aredis_utils import RedisUtils
from pot_libs.logger import log
from unify_api.modules.common.dao.common_dao import user_by_phone_number
from pot_libs.settings import SETTING
from unify_api.modules.users.procedures.jwt_user import auth_phone_verify
from unify_api.modules.common.procedures.multi_lang import load_login_tips


async def wechat_login(args, host):
    """wx小程序登录"""
    # 向后端auth服务器发起认证
    request_body = {
        "code": args.get('code'),
        "encryptedData": args.get('encryptedData'),
        "iv": args.get('iv'),
        "user_info": args.get("user_info"),
        "client_name": args.get("client_name"),
        "host": host,
        "product": args.get("product"),
        "db": SETTING.mysql_db
    }

    try:
        log.info(
            f"request auth_url={SETTING.auth_url} request_body = {request_body}")
        resp_str, status = await AioHttpUtils().post(
            SETTING.auth_url,
            request_body,
            timeout=50,
        )
        log.info(f"request auth_url resp_str={resp_str} status={status}")
        resp = json.loads(resp_str)
        return status, resp
    except Exception as e:
        log.exception(e)
        return 401, {"code": 40001, "data": None, "message": str(e)}


async def app_login(args, host):
    """app登录"""
    # 向后端auth服务器发起认证
    request_body = {
        "client_name": args.get("client_name"),
        "unionid": args.get("unionid"),
        "host": host,
        "product": args.get("product"),
        "db": SETTING.mysql_db
    }
    if not args.get("unionid"):
        return 401, {"code": 40001, "data": None, "message": "unionid is None"}

    try:
        log.info(
            f"request auth_url={SETTING.auth_url} request_body = {request_body}")
        resp_str, status = await AioHttpUtils().post(
            SETTING.auth_url,
            request_body,
            timeout=50,
        )
        log.info(f"request auth_url resp_str={resp_str} status={status}")
        resp = json.loads(resp_str)
        return status, resp
    except Exception as e:
        log.exception(e)
        return 401, {"code": 40001, "data": None, "message": str(e)}


async def web_login(args, host, lang):
    """web登录"""
    # 1. 准备转发给auth服务的参数
    request_body = {
        "code": args['code'],
        "client_name": args.get("client_name"),
        "host": host,
        "db": SETTING.mysql_db
    }
    try:
        # auth_url = "http://0.0.0.0:9000/unify-api/auth"
        log.info(f"web_login auth_url={SETTING.auth_url} "
                 f"request_body = {request_body}")
        resp_str, status = await AioHttpUtils().post(
            SETTING.auth_url,
            request_body,
            timeout=50,
        )
        log.info(f"web_login request auth_url rsp={resp_str} status={status}")
        resp = json.loads(resp_str)
        if status == 301:
            # 跳转填写页面
            tip = load_login_tips("direct_info_page", lang)
            return 301, {"code": 30001,
                         "data": {"wechat_id": resp['reasons'][0]},
                         "message": tip}

        elif status == 200:
            # 成功
            tip = load_login_tips("succeed", lang)
            return 200, {"code": 200, "data": resp, "message": tip}
        else:
            # 失败
            tip = load_login_tips("fail", lang)
            return 401, {"code": 40001, "data": resp, "message": tip}
    except Exception as e:
        log.exception(e)
        return 401, {"code": 401, "data": None, "message": str(e)}


async def third_login(args, host, lang):
    """第三方接口用户名密码登录"""
    user_name = args.get("user_name")
    password = args.get("password")
    err_uname_pwd_tip = load_login_tips("err_uname_pwd", lang)

    # 1. 对参数校验
    if not all([user_name, password]):
        return 401, {"code": 40001, "data": None, "message": err_uname_pwd_tip}

    # 1. 准备转发给auth服务的参数
    request_body = {
        "phone": user_name,
        "password": password,
        "client_name": args.get("client_name"),
        "host": host,
        "product": args.get("product"),
        "db": SETTING.mysql_db
    }
    try:
        log.info(
            f"request auth_url={SETTING.auth_url} request_body = {request_body}")
        resp_str, status = await AioHttpUtils().post(
            SETTING.auth_url,
            request_body,
            timeout=50,
        )
        log.info(f"request auth_url resp_str={resp_str} status={status}")
        resp = json.loads(resp_str)
        if status == 200:
            # 成功
            tip = load_login_tips("succeed", lang)
            return 200, {"code": 200, "data": resp, "message": tip}
        else:
            return 401, {
                "code": 40001,
                "data": resp,
                "message": err_uname_pwd_tip
            }
    except Exception as e:
        log.exception(e)
        return 401, {"code": 40001, "data": None, "message": str(e)}


async def web_third_login(args, host, lang):
    """第三方接口用户名密码登录"""
    user_name = args.get("user_name")
    password = args.get("password")
    err_uname_pwd_tip = load_login_tips("err_uname_pwd", lang)

    # 1. 对参数校验
    if not all([user_name, password]):
        return 401, {"code": 40001, "data": None, "message": err_uname_pwd_tip}

    # 1. 准备转发给auth服务的参数
    request_body = {
        "phone": user_name,
        "password": password,
        "client_name": args.get("client_name"),
        "host": host,
        "db": SETTING.mysql_db
    }
    try:
        log.info(
            f"request auth_url={SETTING.auth_url} request_body = {request_body}")
        resp_str, status = await AioHttpUtils().post(
            SETTING.auth_url,
            request_body,
            timeout=50,
        )
        log.info(f"request auth_url resp_str={resp_str} status={status}")
        resp = json.loads(resp_str)
        if status == 200:
            # 成功
            tip = load_login_tips("succeed", lang)
            return 200, {"code": 200, "data": resp, "message": tip}
        else:
            log.info(f"request resp={resp}")
            return 401, {"code": 40001, "data": None,
                         "message": err_uname_pwd_tip}
    except Exception as e:
        log.exception(e)
        return 401, {"code": 40001, "data": None, "message": str(e)}


async def validation_login(args, host, lang):
    """手机验证码登录"""
    phone = args.get("phone")
    verify_client = args.get("verify")
    client_name = args.get("client_name")
    err_uname_pwd_tip = load_login_tips("err_uname_pwd", lang)

    # 1. 对参数校验
    if not re.match(r'^1[3-9]\d{9}$', phone):
        # 手机号码格式错误
        tip = load_login_tips("err_phone_fmt", lang)
        return 401, {"code": 40001, "data": None, "message": tip}

    if not all([phone, verify_client]):
        return 401, {"code": 40001, "data": None, "message": err_uname_pwd_tip}
    # 效验验证码
    auth_verify = await auth_phone_verify(phone, verify_client)
    if not auth_verify:
        err_vfy_code_tip = load_login_tips("err_vfy_code", lang)
        return 401, {"code": 40001, "data": None, "message": err_vfy_code_tip}

    user = await user_by_phone_number(phone)
    if not user:
        # 当前账号无权限，请联系管理人员
        tip = load_login_tips("account_no_auth", lang)
        return 301, {"code": 30001, "data": None, "message": tip}

    # 1. 准备转发给auth服务的参数
    request_body = {
        "phone": phone,
        "user_id": user["user_id"],
        "client_name": client_name,
        "host": host,
        "db": SETTING.mysql_db
    }
    try:
        log.info(SETTING.auth_url, f"request auth_url={SETTING.auth_url} "
                                   f"request_body = {request_body}")
        resp_str, status = await AioHttpUtils().post(SETTING.auth_url,
                                                     request_body, timeout=50,
                                                     )
        log.info(f"request auth_url resp_str={resp_str} status={status}")
        resp = json.loads(resp_str)
        if status == 200:
            # 成功
            tip = load_login_tips("succeed", lang)
            return 200, {"code": 200, "data": resp, "message": tip}
        else:
            return 401, {
                "code": 40001,
                "data": resp,
                "message": err_uname_pwd_tip
            }
    except Exception as e:
        log.exception(e)
        return 401, {"code": 40001, "data": None, "message": str(e)}


class ExtAuthentication(Authentication):
    """jwt auth, 也是登录逻辑"""

    async def authenticate(self, request, *args, **kwargs):
        args = request.json
        log.info(f"authenticate request.json = {request.json}")
        # 用户名密码账号登录
        if args.get("user_name") == "balabala" and args.get(
                "password") == "balabala" and int(SETTING.debug_mode) == 1:
            return {"user_id": 88}

        client_name = args.get("client_name")
        host = request.host
        user_id, message = 0, "未经认证"
        if client_name == "wechat":
            # 微信登录逻辑
            try:
                user_id, is_success, message = await wechat_login(args, host)
            except Exception as e:
                log.error("wechat_login 出错了")
                log.exception(e)
            else:
                if not is_success:
                    msg = {
                        "user_id": user_id,
                        "message": message
                    }
                    raise exceptions.AuthenticationFailed(json.dumps(msg),
                                                          status_code=40001)
        else:
            # web登录逻辑
            user_id, message = await web_login(args, host)
        if not user_id:
            raise exceptions.AuthenticationFailed(message, status_code=40001)
        return {"user_id": user_id}

    async def store_refresh_token(self, user_id, refresh_token, *args,
                                  **kwargs):
        """auth完成会默认调用"""
        log.info("store_refresh_token")
        await RedisUtils().hset("auth:refresh_toke", user_id, refresh_token)

    async def retrieve_user(self, request, payload, *args, **kwargs):
        if payload:
            user_id = payload.get("user_id", None)
            return {"user_id": user_id}
        else:
            return None

    async def retrieve_refresh_token(self, user_id, *args, **kwargs):
        return await RedisUtils().hget("auth:refresh_toke", user_id)
