# -*- encoding: utf-8 -*-
"""
@File    : UnicomComboPayNotifyController.py
@Time    : 2022/6/29 14:31
@Author  : stephen
@Email   : zhangdongming@asj6.wecom.work
@Software: PyCharm
"""
import logging
import time
import traceback
from urllib.parse import parse_qs, unquote

from django.db import transaction
from django.http import HttpResponse
from django.views import View

from AdminController.CloudServiceManage.AgentOrderController import AgentOrderView
from Controller.UnicomCombo.UnicomComboController import UnicomComboView
from Model.models import Order_Model, UnicomDeviceInfo, UnicomCombo, Device_User
from Object.AliPayObject import AliPayObject
from Object.AliSmsObject import AliSmsObject
from Object.RedisObject import RedisObject
from Object.WechatPayObject import WechatPayObject
from Service.CommonService import CommonService


class UnicomComboPayNotifyView(View):

    def get(self, request, *args, **kwargs):
        request.encoding = 'utf-8'
        operation = kwargs.get('operation')
        return self.validation(request.GET, request, operation)

    def post(self, request, *args, **kwargs):
        request.encoding = 'utf-8'
        operation = kwargs.get('operation')
        return self.validation(request.POST, request, operation)

    def validation(self, request_dict, request, operation):
        if operation == 'ali-notify':
            return self.alipay_notify(request_dict)
        elif operation == 'wechat-notify':
            return self.wechat_notify(request)

    @classmethod
    def alipay_notify(cls, request_dict):
        """
        支付宝网页支付异步回调通知
        参考文档 https://opendocs.alipay.com/open/203/105286
        @param request_dict: 请求参数
        @return: success or fail
        """
        logger = logging.getLogger('info')
        logger.info('联通套餐支付---支付宝支付回调')
        order_id = ''
        redisObj = RedisObject()
        notify_key = 'ansjer:unicom:alipay:{}:str'
        try:
            re_data = request_dict.dict()
            passback_params = re_data['passback_params']
            params = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()])
            activate_type = int(params['activateType'])
            logger.info('支付宝异步回调参数:{},携带参数{}'.format(re_data, params))
            signature = re_data['sign']
            re_data.pop('sign')
            order_id = re_data['out_trade_no']

            # redis加锁，防止订单重复  命令在指定的 key 不存在时，为 key 设置指定的值。存在则返回0
            isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1)
            # 过期时间60秒
            redisObj.CONN.expire(notify_key.format(order_id), 60)
            if not isLock:
                return HttpResponse('fail')

            order_qs = Order_Model.objects.filter(orderID=order_id)
            if not order_qs.exists():
                UnicomComboView().save_order_pay_log(order_id, re_data["trade_no"],
                                                     'unicom/wap/pay/wechat-notify', 'aliPay', 'FAILED', re_data)
                logger.info('系统订单不存在:{}'.format(order_id))
                return HttpResponse('fail')
            order_qs = order_qs.filter(status=0)
            if not order_qs.exists():
                logger.info('订单已支付或退款{}'.format(order_id))
                return HttpResponse('success')
            aliPayObj = AliPayObject()
            alipay = aliPayObj.conf()
            # 异步回调验签
            success = alipay.verify(re_data, signature)
            if not success or re_data["trade_status"] not in ("TRADE_SUCCESS", "TRADE_FINISHED"):
                return HttpResponse('fail')

            UnicomComboView().save_order_pay_log(order_id, re_data["trade_no"],
                                                 'unicom/wap/pay/wechat-notify', 'aliPay', 'SUCCESS', re_data)
            return cls.order_pay_notify(order_id, re_data["trade_no"], activate_type, notify_key.format(order_id),
                                        order_qs, redisObj)
        except Exception as e:
            logger.info('联通套餐订单支付宝支付回调异常:{}'.format(repr(e)))
            redisObj.del_data(key=notify_key.format(order_id))
            return HttpResponse('fail')

    @classmethod
    def wechat_notify(cls, request):
        """
        微信支付异步回调
        参考文档：https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
        @param request: 回调参数 具体参考：https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
        @return: SUCCESS or FAIL
        """
        logger = logging.getLogger('info')
        logger.info('联通套餐支付---微信支付回调')
        order_id = ''
        redisObj = RedisObject()
        notify_key = 'ansjer:unicom:wxpay:{}:str'
        pay = WechatPayObject()
        try:
            re_data = pay.weixinpay_call_back(request.body)
            attach = re_data["attach"]
            parmap = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()])
            activate_type = int(parmap['activateType'])
            logger.info('微信异步回调参数:{},携带参数{}'.format(re_data, parmap))
            trade_status = re_data['result_code']  # 业务结果  SUCCESS/FAIL
            order_id = re_data['out_trade_no']  # 商户订单号
            order_qs = Order_Model.objects.filter(orderID=order_id)
            if not order_qs.exists():
                UnicomComboView().save_order_pay_log(order_id, re_data["transaction_id"],
                                                     'unicom/wap/pay/ali-notify', 'wechatPay', 'FAILED', re_data)
                return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
            order_qs = order_qs.filter(status=0)
            if not order_qs.exists():
                logger.info('订单已支付或退款{}'.format(order_id))
                return cls.wx_return_code()

            if trade_status != 'SUCCESS':
                logger.info('微信支付回调Fail')
                order_qs.update(status=10)
                return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
            check_sign = pay.get_notifypay(re_data)
            if not check_sign:
                logger.info('微信支付回调签名失败')
                return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))

            # redis加锁，防止订单重复
            redisObj = RedisObject()
            isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1)
            redisObj.CONN.expire(notify_key.format(order_id), 60)
            if not isLock:
                return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
            UnicomComboView().save_order_pay_log(order_id, re_data["transaction_id"],
                                                 'unicom/wap/pay/ali-notify', 'wechatPay', 'SUCCESS', re_data)
            return cls.order_pay_notify(order_id, re_data["transaction_id"], activate_type, notify_key.format(order_id),
                                        order_qs,
                                        redisObj, True)
        except Exception as e:
            redisObj.del_data(key=notify_key.format(order_id))
            return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)}))

    @staticmethod
    def wx_return_code():
        return HttpResponse("<xml>\
                                  <return_code><![CDATA[SUCCESS]]></return_code>\
                                  <return_msg><![CDATA[OK]]></return_msg>\
                              </xml>")

    @classmethod
    def order_pay_notify(cls, order_id, trade_no, activate_type, request_key, order_qs, redisObj, is_wechat_pay=False):
        """
        订单支付通知
        @param trade_no: 第三方交易流水号
        @param order_id:订单编号
        @param activate_type: 激活类型
        @param request_key:访问缓存key
        @param order_qs:订单对象
        @param redisObj:缓存对象
        @param is_wechat_pay:是否微信支付
        @return: success or fail
        """
        logger = logging.getLogger('info')
        now_time = int(time.time())
        with transaction.atomic():
            # 支付宝交易凭证号。
            order_qs = order_qs.values('UID', 'unify_combo_id', 'userID_id', 'order_type')
            device_uid = order_qs[0]['UID']
            user_id = order_qs[0]['userID_id']
            combo_id = order_qs[0]['unify_combo_id']
            serial_no = CommonService.query_serial_with_uid(device_uid)
            unicom_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_no).values('iccid')
            if unicom_device_info_qs.exists():
                iccid = unicom_device_info_qs[0]['iccid']
                UnicomComboView.create_combo_order_info(order_id, activate_type,
                                                        iccid, combo_id)
            order_qs.update(trade_no=trade_no, status=1, payTime=now_time, updTime=now_time)
            logger.info('购买联通套餐成功,序列号为：{}'.format(serial_no))
            # 购买套餐成功异步短信推送
            cls.buy_async_sms_sen(user_id, serial_no, combo_id)
            # 检查是否代理商设备
            AgentOrderView.check_agent_service_package(order_id, device_uid, combo_id)
        redisObj.del_data(key=request_key)
        if is_wechat_pay:
            return HttpResponse("<xml>\
                          <return_code><![CDATA[SUCCESS]]></return_code>\
                          <return_msg><![CDATA[OK]]></return_msg>\
                        </xml>")
        else:
            return HttpResponse('success')

    @staticmethod
    def buy_async_sms_sen(user_id, serial_no, combo_id):
        try:
            if not all([user_id, serial_no, combo_id]):
                return True
            user_qs = Device_User.objects.filter(userID=user_id).values('phone')
            if user_qs.exists():
                phone = user_qs.first()['phone']

                combo_qs = UnicomCombo.objects.filter(id=combo_id).values('combo_name')
                if combo_qs.exists():
                    params = u'{"devname":"' + serial_no + '","submittime":"' + \
                             time.strftime("%Y-%m-%d", time.localtime()) + '","name":"' + \
                             combo_qs.first()['combo_name'] + '"}'
                    sign_name = CommonService.confirm_msg_sign_name_with_phone(phone)
                    ali_sms = AliSmsObject()
                    ali_sms.send_code_sms_cloud(phone, params, sign_name, 'SMS_251031744')
            return True
        except Exception as e:
            print(e.args)
            ex = traceback.format_exc()
            print(ex)
            return True
