# coding=utf-8

import json
import xmltodict
import traceback
from django.db import transaction
from django.http import HttpResponse
from rest_framework.views import APIView
from django.conf import settings
from utils.wx.WXBizMsgCrypt import WXBizMsgCrypt
from utils.exceptions import CustomError
from apps.order.models import Pay
from utils.wechatpay import WechatPayNotify
from utils import response_error, response_ok
from apps.log.models import BizLog
from apps.WechatTp.models import WechatTp
from apps.WechatApplet.models import WechatApplet
from alipay.aop.api.util.SignatureUtils import verify_with_rsa
# from apps.WeChatResponse import WechatPayNotify

class CallbackAuthorize(APIView):
    '''验证票据（component_verify_ticket）在第三方平台创建审核通过后，微信服务器会向其 ”授权事件接收URL”
    每隔 10 分钟以 POST 的方式推送 component_verify_ticket 接收 POST 请求后，只需直接返回字符串 success。
    为了加强安全性，postdata 中的 xml 将使用服务申请时的加解密 key 来进行加密'''

    def post(self, request):
        sMsgSignature = request.GET.get('msg_signature')
        sTimeStamp = request.GET.get('timestamp')
        sNonce = request.GET.get('nonce')
        sPostData = request.body.decode('utf-8')

        try:
            component = WechatTp.getDefault()
            if component:
                appid = component.getAppid()
                msg_crypt = WXBizMsgCrypt(component.getToken(), component.getEncodeKey(), appid)
                ret, decryp_xml = msg_crypt.DecryptMsg(sPostData, sMsgSignature, sTimeStamp, sNonce)
                data = json.loads(json.dumps(xmltodict.parse(decryp_xml)))['xml']
                if data['AppId'] == appid:
                    if data['InfoType'] == 'component_verify_ticket':
                        component.refreshVerifyTicket(data['ComponentVerifyTicket'])
                    elif data['InfoType'] == 'unauthorized':
                        authorizer_appid = data['AuthorizerAppid']
                        authorizer = WechatApplet.getByAppidAndComponentAppid(authorizer_appid, appid)
                        if authorizer:
                            authorizer.revoke()
        except:
            pass

        return HttpResponse('success')


class CallbackEvent(APIView):
    '''消息与事件接收'''

    def post(self, request, appid):
        appid = appid
        sMsgSignature = request.GET.get('msg_signature')
        sTimeStamp = request.GET.get('timestamp')
        sNonce = request.GET.get('nonce')
        sPostData = request.body.decode('utf-8')

        try:
            tp = WechatTp.getDefault()
            msg_crypt = WXBizMsgCrypt(tp.getToken(), tp.getEncodeKey(), tp.getAppid())
            ret, decryp_xml = msg_crypt.DecryptMsg(sPostData, sMsgSignature, sTimeStamp, sNonce)
            data = json.loads(json.dumps(xmltodict.parse(decryp_xml)))['xml']
            if data['MsgType'] == 'event':
                app = WechatApplet.getByAppid(appid)
                if data['Event'] == 'weapp_audit_success':  # 代码审核通过
                    app.weapp_audit_success()
                elif data['Event'] == 'weapp_audit_fail':  # 代码审核不通过
                    app.weapp_audit_fail(data['Reason'])
                elif data['Event'] == 'weapp_audit_delay':  # 代码审核延后
                    app.weapp_audit_delay(data['Reason'])
        except:
            pass
        return HttpResponse('success')

class AlipayNotifyView(APIView):
    def check_pay(self, params):
        sign = params.pop('sign', None)
        params.pop('sign_type')
        params = sorted(params.items(), key=lambda e: e[0], reverse=False)
        message = "&".join(u"{}={}".format(k, v) for k, v in params).encode()
        try:
            status = verify_with_rsa(settings.ALIPAY_SETTING['alipay_public_key'].encode('utf-8').decode('utf-8'), message,sign)
            return status
        except:
            return False

    def post(self, request):
        params = request.POST.dict()
        if not self.check_pay(params):
            return HttpResponse('')


        no = request.POST.get('out_trade_no')
        app_id = request.POST.get('app_id')
        notify_type = request.POST.get('notify_type')
        trade_status = request.POST.get('trade_status')
        amount = request.POST.get('total_amount')

        if notify_type != 'trade_status_sync':
            return HttpResponse('')

        if app_id != settings.ALIPAY_SETTING['app_id']:
            return HttpResponse('')

        try:
            with transaction.atomic():
                pay = Pay.getByNo(no)
                if trade_status == 'TRADE_CLOSED':
                    pay.payClosed()
                    BizLog.objects.addnew(None,pay.user, BizLog.INSERT, u'支付取消，pay_no=%s' % no,params)

                if trade_status == 'TRADE_SUCCESS' or trade_status == 'TRADE_FINISHED':
                    pay.paySuccess(float(amount))
                    BizLog.objects.addnew(None,pay.user, BizLog.INSERT, u'支付宝支付成功，pay_no=%s' % no,params)
        except:
            import traceback
            traceback.print_exc()
            return HttpResponse('')
        return HttpResponse('success')


class WechatNotifyView(APIView):

    def dispatch(self, request, *args, **kwargs):
        param = request.body
        appid = kwargs['appid']
        applet = WechatApplet.getByAppid(appid)
        # param = request.body.decode('utf-8')
        notify = WechatPayNotify(param, applet.agent_key)
        try:
            data = notify.handle()
            if not data:
                raise CustomError(u'错误的请求！')

            result_code = data['result_code']
            if result_code != 'SUCCESS':
                raise CustomError(u'错误的请求！')

            no = data['out_trade_no']
            amount = float(data['total_fee']) / 100.0

            with transaction.atomic():
                pay = Pay.getByNo(no)
                pay.paySuccess(amount)
                BizLog.objects.addnew(pay.user, BizLog.INSERT, u'微信支付成功，pay_no=%s' % no, param)
        except Exception as e:
            traceback.print_exc()
            return HttpResponse(WechatPayNotify.response_fail())
        return HttpResponse(WechatPayNotify.response_ok())
