package com.wechat.pay;

import java.security.MessageDigest;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.library.config.ConfigCon;
import com.library.util.ClientInternet;
import com.library.util.Tools;
import com.wechat.pay.WeChatManager.ShortUrl;
import com.wechat.pay.WeChatManager.Token;

/**
 * 小程序管理类
 * @author DengYeBin
 *
 */
public class SmallProgramManager {
	
	/** 记录时间的毫秒数，用作获取access_token */
	public static long Time_Access_Token=0;
	
	/**记录时间的毫秒数，用作获取jsapi_ticket*/
	public static long Time_jsapi_ticket=0;
	
	/**
	 * Access_Token的值
	 */
	private static String Access_Token="";
	
	/**
	 * 页面支付使用权限的时候所需要用的Jsapi_Ticket
	 */
	public static String Jsapi_Ticket="";
	
	/**
	 * 获得access_token
	 * 例子：{"access_token":"v6_-DN1HhXuQATEmX1RnCbj_vWyPmvGdRHzUqm9A0dKZUqQcPfwP_htMddUANclCRBLpK6IOdQiR5unFBvilRjW_Di6bDrLg4QhXeO4xPywPDEdAAAHVW","expires_in":7200}
	 */
	public static String GetAccess_token(){
		long time=System.currentTimeMillis();
		//判断是否距离上一次获得超过生效时间
		if(time>Time_Access_Token){
			String address="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ConfigCon.SmallAppid+"&secret="+ConfigCon.SmallSecret;
			String json=ClientInternet.OpearConnect(address, null, "");
			Token t=Tools.gson.fromJson(json, Token.class);
			Access_Token=t.access_token;
			Time_Access_Token=time+t.expires_in*1000;//保存时间记录
			System.out.println("系统通知：获取一次Access_Token！");
			System.out.println("系统通知："+Access_Token);
			return t.access_token;
		}else{
			return Access_Token;
		}
	}

	/**
	 * 开发者服务器使用登录凭证 code 获取 session_key 和 openid
	 * @author Administrator
	 */
	public static Jscode2session getOpenid(String code){
		String url="https://api.weixin.qq.com/sns/jscode2session?appid="+ConfigCon.SmallAppid+"&secret="+ConfigCon.SmallSecret+"&js_code="+code+"&grant_type=authorization_code";
		String res=ClientInternet.OpearConnect(url, null, "");
		Jscode2session jscode2session=Tools.gson.fromJson(res, Jscode2session.class);
		return jscode2session;
	}
	
	//String scene, String page, int width, boolean auto_color, Object line_color
	/**
	 * 获取小程序二维码，用于分享
	 * @param path 二维码保存地址
	 * @param scene 自定义参数 最大32个可见字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~，其它字符请自行编码为合法字符（因不支持%，中文无法使用 urlencode 处理，请使用其他编码方式）
	 * @param page 必须是已经发布的小程序页面，例如 "pages/index/index" ,根路径前不要填加'/',不能携带参数（参数请放在scene字段里），如果不填写这个字段，默认跳主页面
	 * @return 布尔值，表示获取成功或失败
	 */
	public static boolean getWXQRCodeUnlimit(String path, String scene, String page){
		SmallProgramManager smallProgramManager = new SmallProgramManager();
		WXCodeUnlimit wxCodeUnlimit = smallProgramManager.new WXCodeUnlimit();
		wxCodeUnlimit.scene = scene;
		wxCodeUnlimit.page = page;
//		wxCodeUnlimit.width = width;
//		if(auto_color){
//			wxCodeUnlimit.auto_color = auto_color;
//			wxCodeUnlimit.line_color = line_color;
//		}
//		else{
//			wxCodeUnlimit.auto_color = false;
//			wxCodeUnlimit.line_color = line_color;
//		}
		String postJson = Tools.gson.toJson(wxCodeUnlimit);
		String address="https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+SmallProgramManager.GetAccess_token();
		boolean flag=ClientInternet.OpenConnectForImg(address, "POST", postJson, path);
		return flag;
	}
	
	class WXCodeUnlimit{
		public String scene; //最大32个可见字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~，其它字符请自行编码为合法字符（因不支持%，中文无法使用 urlencode 处理，请使用其他编码方式）
		public String page; //必须是已经发布的小程序页面，例如 "pages/index/index" ,根路径前不要填加'/',不能携带参数（参数请放在scene字段里），如果不填写这个字段，默认跳主页面
//		public String path="pages/home/home"; //必须是已经发布的小程序页面，例如 "pages/index/index" ,根路径前不要填加'/',不能携带参数（参数请放在scene字段里），如果不填写这个字段，默认跳主页面
//		public int width; //二维码的宽度
//		public boolean auto_color; //自动配置线条颜色，如果颜色依然是黑色，则说明不建议配置主色调
//		public Object line_color; //auto_color 为 false 时生效，使用 rgb 设置颜色 例如 {"r":"xxx","g":"xxx","b":"xxx"}
	}
	
	public class Jscode2session{
		public String openid;//用户唯一标识
		public String session_key;//	会话密钥
		public String unionid;//用户在开放平台的唯一标识符。本字段在满足一定条件的情况下才返回
	}
	
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 * 一套生成所有订单参数
	 */
	public static SmallPayAttrbute CreatAllPaream(String spbill_create_ip,String body,String out_trade_no,int total_fee,String WX_Notify_url,String openid){
		String post=getSmallAppletXML(spbill_create_ip, total_fee, out_trade_no,WX_Notify_url,body,openid);
		System.out.println("==="+post);
		String return_res=ClientInternet.OpearConnect("https://api.mch.weixin.qq.com/pay/unifiedorder", null, post);
		System.out.println("==="+return_res);
		String prepay_id=AnalysisXML(return_res);
		return CreatBean(prepay_id);
	}
	
	/**
	 * 生成返回给APP支付的Bean
	 */
	private static SmallPayAttrbute CreatBean(String prepay_id){
		SmallPayAttrbute bean=new SmallPayAttrbute();
		bean.timeStamp=""+System.currentTimeMillis()/1000;
		bean.nonceStr=Md5(""+System.currentTimeMillis());
		bean.packageValue = "prepay_id="+prepay_id;
		bean.signType="MD5";
	    bean.paySign=Md5("appId="+ConfigCon.SmallAppid+"&nonceStr="+bean.nonceStr+"&package="+bean.packageValue+
	    		"&signType=MD5&timeStamp="+bean.timeStamp+"&key="+ConfigCon.Small_APIKey);
	    return bean;
	}
	
	
	/**
	 * 解析下单返回的XML,获得prepay_id，预支付交易会话标识,下单出错则返回空字符
	 * <xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg><appid><![CDATA[wxb1da7561feb15929]]></appid><mch_id><![CDATA[1437388502]]></mch_id><nonce_str><![CDATA[usLgwY7LaXlf4F4m]]></nonce_str><sign><![CDATA[8F77B5A7D701C2E1D98EE6AFC54B09CE]]></sign><result_code><![CDATA[SUCCESS]]></result_code><prepay_id><![CDATA[wx20170209102827423e5aa5ca0083727592]]></prepay_id><trade_type><![CDATA[APP]]></trade_type></xml>
	 */
	private static String AnalysisXML(String XMLcon){
		try {
			Document document=DocumentHelper.parseText(XMLcon);
			Element element=document.getRootElement();
			String return_code=element.elementText("return_code");
			String result_code=element.elementText("result_code");
			if(return_code.equals("SUCCESS") && result_code.equals("SUCCESS")){
				return element.elementText("prepay_id");
			}else{
				return "";
			}
		} catch (DocumentException e) {
			e.printStackTrace();
			return "";
		}
	}
	
	/**
	 * 下单生成的字符串
	 */
	private static String getSmallAppletXML(String spbill_create_ip,int total_fee,String out_trade_no,String WX_Notify_url,String body,String openid){
//		String body="APP支付";
//		String WX_Notify_url=ConfigCon.WeChat_Notify_urlshopBond;
		
		String trade_type="JSAPI";
		String nonce_str=Md5(System.currentTimeMillis()+"");
		
		
		SortedMap<String,String> parameters = new TreeMap<String,String>();  
	    parameters.put("appid", ConfigCon.SmallAppid);  
	    parameters.put("body", body); 
	    parameters.put("mch_id", ConfigCon.Small_Mch_id);  
	    parameters.put("nonce_str", nonce_str);  
	    parameters.put("notify_url",WX_Notify_url ); 
	    parameters.put("out_trade_no", out_trade_no);  
	    parameters.put("spbill_create_ip", spbill_create_ip);  
	    parameters.put("total_fee", ""+total_fee);
	    parameters.put("trade_type", trade_type);
	    parameters.put("openid", openid);
	    
	    String sign=createSign("UTF-8",parameters);;
		
		String con="<xml>";
		con+="<appid>"+ConfigCon.SmallAppid+"</appid>";
		con+="<body>"+body+"</body>";
		con+="<mch_id>"+ConfigCon.Small_Mch_id+"</mch_id>";
		con+="<nonce_str>"+nonce_str+"</nonce_str>";//随机字符串，不长于32位
		con+="<notify_url>"+WX_Notify_url+"</notify_url>";
		con+="<out_trade_no>"+out_trade_no+"</out_trade_no>";
		con+="<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>";//用户端实际ip
		con+="<total_fee>"+total_fee+"</total_fee>";//订单总金额，单位为分
		con+="<trade_type>"+trade_type+"</trade_type>";// 支付类型 
		con+="<openid>"+openid+"</openid>";// 用户标识
		con+="<sign>"+sign+"</sign>";
		con+="</xml>";
		return con;
	}
	
	/** 
	 * 生成下单签名
	 */
	    //定义签名，微信根据参数字段的ASCII码值进行排序 加密签名,故使用SortMap进行参数排序
	private static String createSign(String characterEncoding,SortedMap<String,String> parameters){
	        StringBuffer sb = new StringBuffer();
	        Set es = parameters.entrySet();
	        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 + "&");
	            }
	        }
	        sb.append("key=" + ConfigCon.Small_APIKey);//最后加密时添加商户密钥，由于key值放在最后，所以不用添加到SortMap里面去，单独处理，编码方式采用UTF-8
	        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
	        return sign;
	    }
	    
	
	private static String Md5(String password) {
		try {
			// ʵ���ַ���
			StringBuffer buffer = new StringBuffer();
			// �����ַ���
			char[] chars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
					'A', 'B', 'C', 'D', 'E', 'F' };
			// ������ת���ɶ���������
			byte[] bytes = password.getBytes();
			// ʹ��md5�������?
			MessageDigest md = MessageDigest.getInstance("MD5");
			// ����
			byte[] targ = md.digest(bytes);
			for (byte b : targ) {
				buffer.append(chars[(b >> 4) & 0x0F]);
				buffer.append(chars[b & 0x0F]);
			}
			return buffer.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	
	

}
