# coding=utf-8

import uuid
import requests
import json
import xmltodict
import time
from hashlib import md5
from django.conf import settings
from apps.WechatApplet.models import WechatApplet
from utils.exceptions import CustomError


# 微信支付sign_type
WEIXIN_SIGN_TYPE = 'MD5'
# 服务器IP地址
WEIXIN_SPBILL_CREATE_IP = '39.101.210.163'
# 微信支付用途
# 微信KEY值 【API密钥】
# WEIXIN_KEY = settings.WECHAT['merchant_key']
# 微信统一下单URL
WEIXIN_UNIFIED_ORDER_URL = 'https://api.mch.weixin.qq.com/pay/unifiedorder'

# 微信查询订单URL
WEIXIN_QUERY_ORDER_URL = 'https://api.mch.weixin.qq.com/pay/orderquery'

# 微信支付回调API
WEIXIN_CALLBACK_API = '{}/api/wechat_notify/'.format(settings.SERVER_DOMAIN)

# pc端支付
class WeChatResponse():

    def __init__(self,appid, agent_id=None):
        applet = getAPPID(appid, agent_id)
        self.params = {
            "appid": appid,
            'mch_id': applet.agent_num,
            'nonce_str': '',
            'sign_type': WEIXIN_SIGN_TYPE,
            'sign': '',
            'out_trade_no': '',
        }
        self.prepay_id = None
        self.merchant_key = applet.agent_key

    # 查询订单
    def orderquery(self, out_trade_no):
        self.params['out_trade_no'] = out_trade_no
        self.params['nonce_str'] = generate_nonce_str()
        self.params['sign'] = generate_sign(self.params, self.merchant_key)
        data = xmltodict.unparse({'xml': self.params}, pretty=True, full_document=False).encode('utf-8')
        headers = {'Content-Type': 'application/xml'}
        res = requests.post(WEIXIN_QUERY_ORDER_URL, data=data, headers=headers)
        if res.status_code != 200:
            raise CustomError(u'微信请求失败！')
        result = json.loads(json.dumps(xmltodict.parse(res.content)))

        if result['xml']['return_code'] != 'SUCCESS':
            raise CustomError(u'微信通信失败！[%s]' % result['xml']['return_msg'])
        print(u'微信交易状态！[%s]' % (result['xml']['trade_state_desc']))
        if result['xml']['trade_state'] == 'NOTPAY':
            return result['xml']['total_fee']
            # raise CustomError(u'微信交易状态！[%s]' % (result['xml']['trade_state_desc']))
        # 其他状态，返回金额0
        return 0
        # return result['xml']['total_fee']

def getAPPID(appid, agent_id):
    applet = WechatApplet.objects.filter(authorizer_appid=appid, is_authorize=True)
    if agent_id:
        applet = applet.filter(agent_id=agent_id)
    if applet:
        applet = applet.first()
    else:
        raise CustomError('小程序appid认证失败！')
    return applet

#小程序支付
class WechatAppletPay():

    def __init__(self, appid, agent_id=None):
        applet = getAPPID(appid, agent_id)
        self.params = {
            "appid":  appid,
            "body": applet.nick_name,
            "mch_id": applet.agent_num,
            "nonce_str": '',
            "notify_url": WEIXIN_CALLBACK_API + appid + '/',
            "openid": '',  # 获取小程序openid
            "out_trade_no": '',
            "spbill_create_ip": WEIXIN_SPBILL_CREATE_IP,
            "total_fee": '',
            "trade_type": 'JSAPI',
            "sign":''
        }
        self.prepay_id = None
        self.merchant_key = applet.agent_key



    def weChatUnifiedOrder(self, openid, out_trade_no, total_fee):
        self.params['out_trade_no'] = out_trade_no
        self.params['total_fee'] = int(round(float(total_fee) * 100, 0))
        self.params['nonce_str'] = generate_nonce_str()
        self.params['openid'] = openid
        self.params['sign'] = generate_sign(self.params,self.merchant_key)
        # 拿到封装好的xml数据
        xml_data = xmltodict.unparse({'xml': self.params}, pretty=True, full_document=False).encode('utf-8')
        # 请求微信统一下单URL
        headers = {'Content-Type': 'application/xml'}
        res = requests.post(WEIXIN_UNIFIED_ORDER_URL, data=xml_data, headers=headers)

        if res.status_code != 200:
            raise CustomError(u'微信请求失败！')

        # 回复数据为xml,将其转为字典
        content = json.loads(json.dumps(xmltodict.parse(res.content)))

        if content['xml']['return_code'] != 'SUCCESS':
            raise CustomError(u'微信通信失败！[%s]' % content['xml']['return_msg'])
        if content['xml']['result_code'] != 'SUCCESS':
            raise CustomError(u'微信交易失败！[%s:%s]' % (content['xml']['err_code'],content['xml']['err_code_des']))

        self.prepay_id = content['xml']['prepay_id']

        return self.getPaymentInfo()

    def getPaymentInfo(self):
        data = {
            'appId': self.params['appid'],
            'package': "prepay_id={}".format(self.prepay_id),
            'nonceStr': generate_nonce_str(),
            'timeStamp': str(int(time.time())),
            'signType':'MD5'
        }
        data['paySign'] = generate_sign(data,self.merchant_key)
        return data

class WechatPayNotify():
    def __init__(self, params):
        self.params = params

    def handle(self):
        resp_dict = json.loads(json.dumps(xmltodict.parse(self.params)))['xml']
        return_code = resp_dict['return_code']

        if return_code != 'SUCCESS':
            return None

        if not validate_sign(resp_dict):
            return None

        return resp_dict

    @staticmethod
    def response_ok():
        return_info = {
            'return_code': 'SUCCESS',
            'return_msg': 'OK'
        }
        return generate_response_data(return_info)

    @staticmethod
    def response_fail():
        return_info = {
            'return_code': 'FAIL',
            'return_msg': 'FAIL'
        }
        return generate_response_data(return_info)

def generate_nonce_str():
    """
    生成随机字符串
    """
    return str(uuid.uuid4()).replace('-', '')


def generate_sign(params,merchant_key):
    """
    生成md5签名的参数
    """
    if 'sign' in params:
        params.pop('sign')
    src = '&'.join(['%s=%s' % (k, v) for k, v in sorted(params.items())]) + '&key=%s' % merchant_key
    return md5(src.encode('utf-8')).hexdigest().upper()


def validate_sign(resp_dict):
    """
    验证微信返回的签名
    """
    if 'sign' not in resp_dict:
        return False
    wx_sign = resp_dict['sign']
    sign = generate_sign(resp_dict, '')
    if sign == wx_sign:
        return True
    return False


def generate_response_data(resp_dict):
    """
    字典转xml
    """
    return xmltodict.unparse({'xml': resp_dict}, pretty=True, full_document=False).encode('utf-8')
