package com.upyuns.platform.rs.universal.weixin.api;



import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import com.github.wxiaoqi.security.common.util.MD5;
import com.github.wxiaoqi.security.common.util.MD5Util;
import com.github.wxiaoqi.security.common.util.OrderUtil;
import com.github.wxiaoqi.security.common.util.process.SystemConfig;
import com.upyuns.platform.rs.universal.utils.RequestHandler;
import com.upyuns.platform.rs.universal.utils.WeiXinPayUtil;
import com.upyuns.platform.rs.universal.utils.WxPrepay;
import com.upyuns.platform.rs.universal.weixin.util.HTTPUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import com.alibaba.fastjson.JSONObject;

/**
 * 微信调起支付类
 * 
 * @author Sunlight
 * 
 */
@Slf4j
public class WXPay {
	/**
	 * JSAPI支付
	 * @param total_fee
	 * @param body
	 * @param notify_url
	 * @param orderNo
	 * @param spbill_create_ip
	 * @param openid
	 * @return
	 */

	public static String webPay(String total_fee,String body,String notify_url,String orderNo,String spbill_create_ip,String openid,String wyAppid){
		WXPrepay prePay = new WXPrepay();
		if (StringUtils.isBlank(wyAppid)){
			wyAppid=SystemConfig.WINXIN_AppID;
		}
		prePay.setAppid(wyAppid);//pay.getAppId()
		prePay.setBody(body);
		prePay.setPartnerKey(SystemConfig.WINXIN_PARTNER_KEY);//pay.getPartnerKey()
		prePay.setMch_id(SystemConfig.WINXIN_PARTNER);//pay.getPartnerId()
		prePay.setNotify_url(notify_url);
		prePay.setOut_trade_no(orderNo);
		prePay.setSpbill_create_ip(spbill_create_ip);//"123.12.12.123"
		prePay.setTotal_fee(total_fee);
		prePay.setTrade_type("JSAPI");
		prePay.setOpenid(openid);
        //此处添加获取openid的方法，获取预支付订单需要此参数！！！！！！！！！！！ 
		// 获取预支付订单号
		String prepayid = prePay.submitXmlGetPrepayId(1);
		System.out.println("获取的预支付订单是：" + prepayid);
		//PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);//获取prepayid的请求类
		//logger.info("预支付签名："+prepayReqHandler.createSHA1Sign());
		String jsParam = "";
		if (prepayid != null && prepayid.length() > 10) {
			// 生成微信支付参数，此处拼接为完整的JSON格式，符合支付调起传入格式
			jsParam = WXPay.createPackageValueWeb(wyAppid, SystemConfig.WINXIN_PARTNER_KEY, prepayid);
		
		}
		return jsParam;
	}


	
	/**
	 * 公众号生成签名
	 * @param appid
	 * @param appKey
	 * @param prepay_id
	 * @return
	 */
	public static String createPackageValueWeb(String appid, String appKey, String prepay_id)  {
	    JSONObject res = new JSONObject();
		res.put("appId", appid);
		String timeStamp = OrderUtil.GetTimestamp();
		res.put("timeStamp", timeStamp);
		Random random = new Random();
		String randomStr = MD5.GetMD5String(String.valueOf(random.nextInt(10000)));
		res.put("nonceStr", MD5Util.MD5Encode(randomStr, "utf-8").toLowerCase());//
		res.put("package", "prepay_id=" + prepay_id);//
		res.put("signType", "MD5");
		SortedMap<String, String> nativeObj = new TreeMap<String, String>();
		nativeObj.put("appId", appid);
		nativeObj.put("nonceStr", MD5Util.MD5Encode(randomStr, "utf-8").toLowerCase());
		nativeObj.put("package", "prepay_id=" + prepay_id);
		nativeObj.put("signType", "MD5");
		nativeObj.put("timeStamp", timeStamp);
		res.put("paySign", createSignWeb(nativeObj, appKey));
		return  res.toJSONString();
	}
	/**
	 * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。公众号生成加密的方式
	 */
	public static String createSignWeb(SortedMap<String, String> packageParams, String AppKey) {
		StringBuffer sb = new StringBuffer();
		Set es = packageParams.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + AppKey);
		log.info("-----签名sign==="+sb.toString());
		String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
		return sign;
	}


	/**
	 * app支付
	 * @param body 商品详情
	 * @param notify_url 回调地址
	 * @param orderNo 订单号
	 * @param spbill_create_ip 移动端的IP
	 * @return
	 */
	public static String apppay(String total_fee,String body,String notify_url,String orderNo,String spbill_create_ip, int version)
	{
		boolean isWeixinPayConfigedForAppStore = (0 == version);
		WXPrepay prePay = new WXPrepay();
		prePay.setBody(body);
		if (isWeixinPayConfigedForAppStore) {
			prePay.setAppid(SystemConfig.APP_ID);//pay.getAppId()
			prePay.setPartnerKey(SystemConfig.APP_PARTNER_KEY);//pay.getPartnerKey()
			prePay.setMch_id(SystemConfig.APP_PARTNER);//pay.getPartnerId()
			prePay.setTrade_type(SystemConfig.APP_TRADE_TYPE);
		} else {
			prePay.setAppid(SystemConfig.APP_ID_IOS);//pay.getAppId()
			prePay.setPartnerKey(SystemConfig.APP_PARTNER_KEY_IOS);//pay.getPartnerKey()
			prePay.setMch_id(SystemConfig.APP_PARTNER_IOS);//pay.getPartnerId()
			prePay.setTrade_type(SystemConfig.APP_TRADE_TYPE_IOS);
		}
		prePay.setNotify_url(notify_url);
		prePay.setOut_trade_no(orderNo);
		prePay.setSpbill_create_ip(spbill_create_ip);//"123.12.12.123"
		prePay.setTotal_fee(total_fee);
        //此处添加获取openid的方法，获取预支付订单需要此参数！！！！！！！！！！！ 
		// 获取预支付订单号
		String prepayid = prePay.submitXmlGetPrepayId(0);
		String jsParam = "";
		if (prepayid != null && prepayid.length() > 10) {
			// 生成微信支付参数，此处拼接为完整的JSON格式，符合支付调起传入格式
			log.error("微信支付>>>>>>>>>：\n isWeixinPayConfigedForAppStore=" + isWeixinPayConfigedForAppStore);
			log.error("prepayid=" + prepayid);
			log.error("SystemConfig.APP_PARTNER_IOS=" + SystemConfig.APP_PARTNER_IOS);
			log.error("SystemConfig.APP_ID_IOS=" + SystemConfig.APP_ID_IOS);
			log.error("SystemConfig.APP_PARTNER_KEY_IOS=" + SystemConfig.APP_PARTNER_KEY_IOS);
			log.error("SystemConfig.APP_TRADE_TYPE_IOS=" + SystemConfig.APP_TRADE_TYPE_IOS);
			if (isWeixinPayConfigedForAppStore) {
				jsParam = createPackageValue(SystemConfig.APP_ID, SystemConfig.APP_PARTNER, prepayid, version);
			} else {
				jsParam = createPackageValue(SystemConfig.APP_ID_IOS, SystemConfig.APP_PARTNER_IOS, prepayid, version);
			}
		}
		return jsParam;
	}
	
	
    /**
     * app 生成签名
     * @param appid
     * @param appKey
     * @param prepay_id
     * @return
     */
	public static String createPackageValue(String appid, String appKey, String prepay_id, int version)  {

		
		JSONObject res = new JSONObject();
		
		res.put("appid", appid);
		Random random = new Random();
		String randomStr = MD5.GetMD5String(String.valueOf(random.nextInt(10000)));
		res.put("noncestr", MD5Util.MD5Encode(randomStr, "utf-8").toLowerCase());//
		res.put("package", "Sign=WXPay");//"prepay_id=" + prepay_id
		res.put("partnerid", appKey);
		res.put("prepayid", prepay_id);
		String timeStamp = OrderUtil.GetTimestamp();
		res.put("timestamp", timeStamp);
		//参考以下两个方法
		//https://pay.weixin.qq.com/wiki/tools/signverify/
		//https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2
		SortedMap<Object,Object> nativeObj = new TreeMap<Object,Object>();
		nativeObj.put("appid", appid);
		nativeObj.put("package", "Sign=WXPay");
		nativeObj.put("partnerid", appKey);
		nativeObj.put("prepayid", prepay_id);
		nativeObj.put("noncestr", MD5Util.MD5Encode(randomStr, "utf-8").toLowerCase());//MD5Util.MD5Encode(randomStr, "utf-8").toLowerCase()
		nativeObj.put("timestamp", timeStamp);
		res.put("sign", createSign("UTF-8",nativeObj, version));
		return res.toString();

	}
	
	
	/** 
     * app微信支付签名算法sign 
     * @param characterEncoding 
     * @param parameters 
     * @return 
     */  
	public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters, int version){  
        StringBuffer sb = new StringBuffer();  
        Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序（升序）  
        Iterator it = es.iterator();  
        while(it.hasNext()) {  
            Map.Entry entry = (Map.Entry)it.next();  
            String k = (String)entry.getKey();  
            Object v = entry.getValue();  
            if(null != v && !"".equals(v)   
                    && !"sign".equals(k) && !"key".equals(k)) {  
                sb.append(k + "=" + v + "&");  
            }  
        }  
        // app store 微信支付
        if (0 == version) {
        	sb.append("key=" + SystemConfig.APP_PARTNER_KEY);
        } else {
        	sb.append("key=" + SystemConfig.APP_PARTNER_KEY_IOS);
        }
		log.error("version：" + version);
		log.error("SystemConfig.APP_PARTNER_KEY_IOS=" + SystemConfig.APP_PARTNER_KEY_IOS);
		log.error("签名前是：" + sb.toString());
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  
        return sign;  
    }  

	
	
	
	/*public static void main(String[] args) {  
		String Key = "cnitr89201000cnitr89201000CNITR5";
        System.out.println(">>>模拟微信支付<<<");  
        System.out.println("==========华丽的分隔符==========");  
        
        
        jsParam={
        	    "appId": "wxbd892cbfd413fe5d",
        	    "nonceStr": "31547a539dc23628bfbee986b27c9fe0",
        	    "package": "prepay_id=wx201604151714339c6dbe5f130465780715",
        	    "paySign": "790DD69BD895C7651773A528B34F93DA",
        	    "signType": "MD5",
        	    "timeStamp": "1460711673"
        	}
        
        
        //微信api提供的参数  
        String appid = "wxbd892cbfd413fe5d";  
        String mch_id = "1311800701";  
        String device_info = "1000";  
        String body = "test";  
        String nonce_str = "ibuaiVcKdpRxkhJA";  
          
        SortedMap<String,String> parameters = new TreeMap<String,String>();  
        parameters.put("appId", "wxbd892cbfd413fe5d");  
        parameters.put("nonceStr", "31547a539dc23628bfbee986b27c9fe0");  
        parameters.put("signType", "MD5");  
        parameters.put("timeStamp", "1460711673");  
        parameters.put("package", "prepay_id=wx201604151714339c6dbe5f130465780715");  
     
          
       // String characterEncoding = "UTF-8";  
        String weixinApiSign = "3E3AECED3FD250CBB22EBAC64E4913C1";  
        System.out.println("微信的签名是：" + weixinApiSign);  
        String mySign = createSignWeb(parameters,Key);  
        System.out.println("我     的签名是："+mySign);  
          
        if(weixinApiSign.equals(mySign)){  
            System.out.println("恭喜你成功了~");  
        }else{  
            System.out.println("注定了你是个失败者~");  
        }  
          
        String userAgent = "Mozilla/5.0(iphone;CPU iphone OS 5_1_1 like Mac OS X) AppleWebKit/534.46(KHTML,like Geocko) Mobile/9B206 MicroMessenger/5.0";  
          
        char agent = userAgent.charAt(userAgent.indexOf("MicroMessenger")+15);  
          
        System.out.println("微信的版本号："+new String(new char[]{agent}));  
    } 
	*/

	/**
	 *获取h5支付支付参数并返回中间页链接
	 * @param amount
	 * @param spbill_create_ip
	 * @param orderNo
	 * @param activityId
	 * @param token
	 * @param body
	 * @param notify_url
	 * @return
	 */
	public static String getH5PayParam(String amount,String spbill_create_ip, String orderNo, String activityId, String token, String body,String notify_url) {
		WXPrepay prePay = new WXPrepay();
		prePay.setAppid(SystemConfig.WINXIN_AppID);//pay.getAppId()
		prePay.setBody(body);
		prePay.setPartnerKey(SystemConfig.WINXIN_PARTNER_KEY);//pay.getPartnerKey()
		prePay.setMch_id(SystemConfig.WINXIN_PARTNER);//pay.getPartnerId()
		prePay.setNotify_url("https://"+SystemConfig.weixinHost+"/icircle/activity/notice.do");
		prePay.setOut_trade_no(orderNo);
		prePay.setSpbill_create_ip(spbill_create_ip);//"123.12.12.123"
		prePay.setTotal_fee(amount);
		prePay.setTrade_type("MWEB");
		log.error("getH5PayParam->payOrderDto:{},appId:{},mchId:{},partnerKey:{},subMchId:{}",
				prePay.getAppid(), prePay.getMch_id(), prePay, SystemConfig.WINXIN_AppID);
			
			String xmlStr = prePay.getPackage();
		    log.error("xmlStr====="+xmlStr);
			String response_body = HTTPUtils.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlStr,
					"text/xml; charset=UTF-8", "UTF-8", null, null);
		    log.error("response_body====="+response_body);
			String mweb_url = analysisXML(response_body, "mweb_url");
			log.error("before->append mweb_url:{},,response_body:{}", mweb_url, response_body);
			try {
					mweb_url += "&redirect_url="
							+ URLEncoder.encode(notify_url + "&token=" + token + "&payed=1", "UTF-8");
				} catch (UnsupportedEncodingException e) {
					log.error(e.getMessage(), e);;
				}

		   log.error("after->append mweb_url:{},isIos:{}", mweb_url);
			return mweb_url;
		
		
	}
	/**
	 * 解析指定xml字符串，获取指定节点名称的文本信息
	 */
	private static String analysisXML(String xmlStr, String nodeName) {
		Document document;
		try {
			document = DocumentHelper.parseText(xmlStr);
			Element rootElement = document.getRootElement();
			Node node = rootElement.selectSingleNode("//" + nodeName);
			if (node == null)
				return null;
			return node.getText();

		} catch (DocumentException e) {
			log.error(e.getMessage(), e);;
		}
		return null;
	}
	public static void main(String[] args) {
		String xmlStr="<xml><appid>wx81470220f10b266e</appid>"+
		"<body><![CDATA[参加活动 【活动名称】的报名费]]></body>"+
		"<mch_id>1423414902</mch_id>"+
		"<nonce_str>0DBCF39D413231953D442F2F17F80CD5</nonce_str>"+
		"<notify_url>http://kcscl.qzlife.net/icircle/activity/notice.do</notify_url>"+
		"<out_trade_no>20180821180143000001</out_trade_no>"+
		"<sign><![CDATA[C948A38E3875E7B5D2F003E73D129391]]></sign>"+
		"<spbill_create_ip>119.145.105.2</spbill_create_ip>"+
		"<sub_mch_id>1511773781</sub_mch_id>"+
		"<total_fee>1</total_fee>"+
		"<trade_type>MWEB</trade_type>"+
		"</xml>";
		System.out.println(1);
		String response_body = HTTPUtils.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlStr,
				"text/xml; charset=UTF-8", "UTF-8", null, null);
		System.out.println(response_body);
	}

	public static String getPackage(String total_fee,String body,String notify_url,String orderNo,String spbill_create_ip,String openid,String appid,String appsecret){
		Map<String,String> map = new LinkedHashMap<String,String>();
		Random random = new Random();
		String randomStr = MD5.GetMD5String(String.valueOf(random.nextInt(10000)));
		String noceStr = MD5Util.MD5Encode(randomStr, "utf-8").toLowerCase();
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("appid",appid);
		packageParams.put("mch_id", SystemConfig.WINXIN_PARTNER);
		packageParams.put("nonce_str", noceStr);
		packageParams.put("body", body);
		packageParams.put("attach", "");
		packageParams.put("out_trade_no", orderNo);

		// 这里写的金额为1 分到时修改
		packageParams.put("total_fee",total_fee);
		packageParams.put("spbill_create_ip", spbill_create_ip);
		packageParams.put("notify_url", notify_url);

		String trade_type = "JSAPI";
		packageParams.put("trade_type", trade_type);
		packageParams.put("openid", openid);

		RequestHandler reqHandler = new RequestHandler(null, null);
		reqHandler.init(appid, appsecret, SystemConfig.WINXIN_PARTNER_KEY);
		String sign = reqHandler.createSign(packageParams);


		WxPrepay wxPrepay = new WxPrepay();
		wxPrepay.setAppid(appid);
		wxPrepay.setMch_id(SystemConfig.WINXIN_PARTNER);
		wxPrepay.setNonce_str(noceStr);
		wxPrepay.setSign(sign);
		wxPrepay.setBody(body);
		wxPrepay.setOut_trade_no(orderNo);
		wxPrepay.setTotal_fee(total_fee);
		wxPrepay.setSpbill_create_ip(spbill_create_ip);
		wxPrepay.setNotify_url(notify_url);
		wxPrepay.setTrade_type(trade_type);
		wxPrepay.setOpenid(openid);
		wxPrepay.setAttach("");

		String xml = WeiXinPayUtil.toXml(wxPrepay);
		log.error("post_prepay_xml: " + xml);
		//获取prepay_id
		map = StringtoMap(WeiXinPayUtil.getPrepayId(xml,"POST"));

		//获取prepay_id后，拼接最后请求支付所需要的package
		SortedMap<String, String> finalpackage = new TreeMap<String, String>();
		String timestamp = OrderUtil.GetTimestamp();
		String packages = "prepay_id="+map.get("prepay_id");
		finalpackage.put("appId", appid);
		finalpackage.put("timeStamp", timestamp);
		finalpackage.put("nonceStr", noceStr);
		finalpackage.put("package", packages);
		finalpackage.put("signType", "MD5");
		//要签名
		String finalsign = reqHandler.createSign(finalpackage);

		String finaPackage = "\"appId\":\"" + appid + "\",\"timeStamp\":\"" + timestamp
				+ "\",\"nonceStr\":\"" + noceStr + "\",\"package\":\""
				+ packages + "\",\"signType\" : \"MD5" + "\",\"paySign\":\""
				+ finalsign + "\"";

		return finaPackage;
	}

	public static   Map<String,String> StringtoMap(String str){
		log.error("respon_prepay_xml: " + str);
		Map<String,String> map = new LinkedHashMap<String,String>();

		try {
			Document document = DocumentHelper.parseText(str);
			Element root = document.getRootElement();
			List<Element> elementList = root.elements();
			for(Element e : elementList){
				map.put(e.getName(), e.getText());
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			log.error(e.getMessage(), e);;
		}
		return map;
	}






}