package com.rrtx.services.pay.weixin;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

public class WxUtil {

	private static final String ALGORITHM = "AES/GCM/NoPadding";
	private static final int TAG_LENGTH_BIT = 128;
	private static final int NONCE_LENGTH_BYTE = 12;
	private static final String AES_KEY = "aNeIu3mTcUF0iEMsyOg2iici1FLxGjWU"; // APIv3密钥
	private static final String TRANSFORMATION_PKCS1Padding = "RSA/ECB/PKCS1Padding";
	private static final String MCH_ID = "1530165211";
	private static final String CERT_PATH  = System.getProperty("os.name").toLowerCase().startsWith("win") 
			? "D:\\temp\\1530165211_20190328_cert\\apiclient_cert.p12" : "/root/nginx/html/personalpaynet/apiclient_cert.p12";
	public static void main(String args[]) throws Exception {
//		uploadFile("https://avatar.csdn.net/2/7/C/3_cover_chan.jpg");
		// 统一下单
//		unifiedorder();
		// 申请入驻
//		sendMechInfo();
		// 查看申请状态
//		checkMchStt();
		// 更新用户信息
//		updateName();
		// getCertficates();
		// String cert = aesgcmDecrypt("c ertificate",
		// "3efb0414b880",
		// "kSM6As7smX5XJ6f7bxOS3Mf/4XAPzUjrcOHFLaEmMSRMwKh9aZ/JL7ezxH94ATSkIKye9yZk8xQ9TApOTR4c5AbhNkDu/DYgpdAHBmkV4sCM5G6Wvx4HwC+xVXKjeziDKOJK0RxEZkBMfJz19jKYr/xNV0j8nQVcYKr7yPl50jXHJeIYEZamkr+6WjE3pdd4wT7C8sZ6cj3EoMihAxGpCbdu2koED9LpjYRcVt9CGljK0gRn54kIfArwMfeI3anhmivi4X/fj4d0wlRAWAnsSjU9DJBRWcSvA3sEXoDUBb10K4M3qfDkIE+CJoZKWtgMymMBYqzKmKAik95OgQcv1dtSlAAI3ImGlKE4KIC/LvJl4e4O9MbQGdZh3iIWuPifW81Z6wB5ZvFBIRvSi1QH2GJMq/bPyI3S0SxGij6wvV2AK+fE4LGj2aVPrMxnLK6iIx3OX1c8vmT0HWO57UroIG3y2Aii0HAr6wgCle+xDgP8TBtXDhE0kWucmNUJCT2RtqVAKL+L9Gz5Ov1SVhtDPVaAjDhucss/5ayPXc7TDtnJDW/W/gSCRvg/sfoSv+5czrH9ixrthd4Px5kEu3CJHxacUCV4Gzm9l/G1UAhGOa5ibPztSx1rchA4RrjUDlgWw8DhlFBquN/oo/RRL2xKgCZXBIuIM71lDT42c+DuNwoRQNEdztSH6wlMg8JDmXo8AgScIhxOsQDWhh2z4mbrcnYOKtmn7AIGVyml260GuXqXazXJ9GzMs18fWzuLiQXpFswwDmVaQspAPKBiGxai3ywZ3VoT/AsM83fGIoASZXrKSPB3zbQOlxvq9loVyeb7gQacQl4juloVygCZR37Ve543UsbeZgr5Gyt5S6HU8vImY+aaIpxUGDLgaDwRpxO5n3lXb+9KyPdBtd02ZfIjEGY6K6FbdbUbrA/3dFc2532JwXbNkpHK/aUQM+4DbMelvqlNfal206WV2GRAKNfMzY9escP4GLKeimWIVGlkQfZwrwOAbXyNqvIahPm7nCBDeio0oiy0Ohw2wSL9gyfpFcDbOIHDY/lktAi5Zhqeb1wlehXk4c8rUYr5XSFbSbhxCszjZRv6MB34Z43o6FkGIlMXO0JUSyMC/IqYKnILocNEmG9K1fa5APVl0bGcJIXkstvzIj7kIVvg63Kj+KeN4Y3xRRAq3fJ1PitQWAJ+wVOvIEJxAj3QAox6KJZFv6X9V7TSms3oiBph9MeJJ+7Mg6KxekMmpvILF2y61h5dSuPlG+7fcD/FQAnlRe7y4erhjlL6qc5Q+CJXACygfx2/7l7QNZLdMR3XaoZWJk17BHFy7UvM0JYROnpv2Sj0wXXDmUkl2WBgaUGwz2Q7RJpAb7wUv96U+/Zduw38gBSJe1EbOuYjJ23Oil0l1cb+FQ1hKnQm+lLiR7F67qSGA0X/0GwnRgPKK3cBUZt1Qqxw2JRv9kzGiXw6WlXRZiyvpqgZLYYt6ZB8ZERJX8NGesBdW76VEbrwh6EaQReDBMHPc5cfGgIeqcLnIfDJwRzHhPIZ9A3zUyLAVmGtTfLyg+qD+dxfHNJ1gZxx7eRJ6+w1s5z4TUnS9SueNnDEpDOdXujaVX+0tVW96EfxckBSVV8nnN/LpsHoneZcui/aJxmlUke1zZxCPuRlB+rW7WHBqqGFTYe83KCXPvfC+grGjyz9OuQao8GCEnILEuhUTo+bfrtPPnpdF4ljnkvuheNEev9DTm2iulGat+duiPB0e9qCQ0c4YyxSGA+aPwDB7axJOHgxeDXGH0QRJXUM8iYRrXa3qlrB+ZOnVwJyQNYyylZkOUhTdkgN5jQXIM2kxrgDzE355EHrNJRGTgfGjg9WYlW5JjbMY5uExZmuyt6/xakxtiKNkv4zGeGvxqspPwkP9OKkqJGiN02Yd+p/CFhhX6uVjzmZ");
		// System.out.println(cert);
	}
	
	/**
	 * 上传图片到微信服务器
	 * @param httpUrlPath 图片HTTP地址
	 * @return
	 *   media_id=7vanu_brY7Aaqti
	 * @throws Exception
	 */
	public static Map uploadFile(String httpUrlPath) throws Exception {
		String retUpload = WxUploadFile.upload(httpUrlPath, MCH_ID, CERT_PATH, "https://api.mch.weixin.qq.com/secapi/mch/uploadmedia", AES_KEY);
		//解析XML存入Map
		Map map = XMLUtil.doXMLParse(retUpload);
		System.out.println("返回报文：" + map);
		return map;
	}

	/**
	 *  微信统一下单
	 *  https://api.mch.weixin.qq.com/pay/unifiedorder
	 * @param payNo 支付流水号，不可重复
	 * @param amt 交易金额(以分为单位)
	 * @param notifyUrl 后台通知URL
	 * @param body 交易产品名称
	 *  @param openId openId
	 *  @param appId appId
	 * @return Map
	 *      prepay_id :预支付交易会话标识
	 *      nonce_str: 通知字符串
	 * @throws Exception
	 */
	public static Map unifiedorder(String payNo, String amt, String notifyUrl, String body, String openId, String appId) throws Exception {
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		packageParams.put("appid", "wx10f4bf0a8faf3374");
		packageParams.put("mch_id", MCH_ID);
		packageParams.put("sub_appid", "wxfdb9d13de2155f5a");
		// 1530443531 ---张宗振
		packageParams.put("sub_mch_id", "1530460381");
		packageParams.put("sign_type", "HMAC-SHA256");
		packageParams.put("nonce_str", System.currentTimeMillis() + "");
		packageParams.put("body", body);
		packageParams.put("out_trade_no", payNo);
		packageParams.put("total_fee", amt);
		packageParams.put("spbill_create_ip", "123.12.12.123");
		packageParams.put("notify_url", notifyUrl);
		packageParams.put("trade_type", "JSAPI");
		packageParams.put("sub_openid", openId);
		String sign = PayCommonUtil.createSign4HMAC("UTF-8", packageParams, AES_KEY);

		packageParams.put("sign", sign);

		String requestXML = PayCommonUtil.getRequestXml(packageParams);
		System.out.println("请求：" + requestXML);
		// 得到含有prepay_id的XML
		String resXml = HttpUtil.postData("https://api.mch.weixin.qq.com/pay/unifiedorder", requestXML);
		System.out.println("返回：" + resXml);
		//解析XML存入Map
		Map map = XMLUtil.doXMLParse(resXml);
		return map;
	}
	

	public static Map updateName() throws Exception {
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		packageParams.put("version", "1.0");
		packageParams.put("mch_id", MCH_ID);
		packageParams.put("nonce_str", System.currentTimeMillis() + "");
		packageParams.put("sign_type", "HMAC-SHA256");
		packageParams.put("sub_mch_id", "1530443531");
//		packageParams.put("merchant_name", "报团小助手");
		packageParams.put("cert_sn", "46AAB6F543C75F9C152FDBEC21819AC1584CCBAB");
		
		
		String sign = PayCommonUtil.createSign4HMAC("UTF-8", packageParams, AES_KEY);

		packageParams.put("sign", sign);

		String requestXML = PayCommonUtil.getRequestXml(packageParams);
		System.out.println("请求报文：" + requestXML);
		//得到含有prepay_id的XML
		String resXml = HttpUtil.postData("https://api.mch.weixin.qq.com/applyment/micro/modifycontactinfo", requestXML, MCH_ID, CERT_PATH);
		//解析XML存入Map
		Map map = XMLUtil.doXMLParse(resXml);
		System.out.println("返回报文：" + map);
		return map;
	}
	
	/**
	 * 查看申请状态
	 * https://api.mch.weixin.qq.com/applyment/micro/getstate
	 * @return
	 * 	applyment_state :申请状态 
	 *     AUDITING:审核中 
		   REJECTED:已驳回 
		   FROZEN:已冻结 
		   TO_BE_SIGNED:待签约 
		   FINISH:完成
		sub_mch_id:小微商户号
		签约链接 :当申请状态为TO_BE_SIGNED或FINISH时才返回
	 * @throws Exception 
	 */
	public static Map checkMchStt(String applymentId) throws Exception {
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		packageParams.put("version", "1.0");
		packageParams.put("mch_id", MCH_ID);
		packageParams.put("nonce_str", System.currentTimeMillis() + "");
		packageParams.put("sign_type", "HMAC-SHA256");
		packageParams.put("applyment_id", applymentId);
		
		String sign = PayCommonUtil.createSign4HMAC("UTF-8", packageParams, AES_KEY);

		packageParams.put("sign", sign);

		String requestXML = PayCommonUtil.getRequestXml(packageParams);
		System.out.println("请求报文：" + requestXML);
		//得到含有prepay_id的XML
		String resXml = HttpUtil.postData("https://api.mch.weixin.qq.com/applyment/micro/getstate", requestXML, MCH_ID, CERT_PATH);
		//解析XML存入Map
		Map map = XMLUtil.doXMLParse(resXml);
		System.out.println("返回报文：" + map);
		return map;
	}
	
	/**
	 * 申请入驻
	 * https://api.mch.weixin.qq.com/applyment/micro/submit
	 * @param flowNo 申请流水号
	 * @param idCardCopyMeaid 身份证正面
	 * @param idCard_national 身份证国徽面照片 
	 * @param idCardNo 身份证号码 
	 * @param cardStartDate 身份证开始日期 【1970-01-01】
	 * @param cardEndTime 身份证结束日期 ，长期【长期】
	 * @param pname 身份证姓名
	 * @param bankCardNo 银行卡号
	 * @param bankName 开户银行
	 * @param bankAddNo 开户银行省市编码
	 * @param merchatSortName 商户简称
	 * @param mobileNo 手机号
	 * @return
	 *   applyment_id:微信支付分配的申请单号 
	 * @throws Exception
	 */
	public static Map sendMechInfo(String flowNo, String idCardCopyMeaid, String idCard_national, String idCardNo, 
			String cardStartDate, String cardEndTime, String pname,
			String bankCardNo, String bankName, String bankAddNo, String merchatSortName, String mobileNo) throws Exception {
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		packageParams.put("version", "3.0");
		packageParams.put("cert_sn", "46AAB6F543C75F9C152FDBEC21819AC1584CCBAB");
		packageParams.put("mch_id", MCH_ID);
		packageParams.put("nonce_str", System.currentTimeMillis() + "");
		packageParams.put("sign_type", "HMAC-SHA256");
		// TODO 服务商自定义的申请唯一编号
		packageParams.put("business_code", flowNo);
		packageParams.put("id_card_copy", idCardCopyMeaid);
		packageParams.put("id_card_national", idCard_national);
		String name = WxRSAEncrypt.rsaEncrypt(pname);
		packageParams.put("id_card_name", name);
		packageParams.put("id_card_number", WxRSAEncrypt.rsaEncrypt(idCardNo));
		if("9999-99-99".equals(cardEndTime)) {
			cardEndTime = "长期";
		}
		String vadTime = "[\"" + cardStartDate + "\", \"" + cardEndTime + "\"]";
		packageParams.put("id_card_valid_time", vadTime);
		packageParams.put("account_name", name);
		packageParams.put("account_bank", bankName);
		// 中国,山东省,济南市,历下区
		packageParams.put("bank_address_code", bankAddNo);
		packageParams.put("account_number", WxRSAEncrypt.rsaEncrypt(bankCardNo));
		packageParams.put("store_name", "新店");
		packageParams.put("store_address_code", "110000");
		packageParams.put("store_street", "新店广场");
		packageParams.put("store_entrance_pic", "AkTafDFlWU59UF9aVVoP_5lstEnJ7UzmWx8mW5rt_RhzcAD1-J2y1iLUqVZv1vtSdBsPSAhT4d7XrW8DxI9uFHiY-Ky9lPsJdcmEm4qeEdc");
		packageParams.put("indoor_pic", "AkTafDFlWU59UF9aVVoP_6v37dD0WfV6SwHGQvzN8k2Cx_NnYLsH4TzP3RY0PHcPuYB_6vVbiU9iK1CBuDQfjlAynCFhCNd4RX6KCSbV2Co");
		packageParams.put("merchant_shortname", merchatSortName); // 商户简称 
		packageParams.put("service_phone", mobileNo); // 客服电话
		packageParams.put("product_desc", "线下零售");
		packageParams.put("rate", "0.38%");
		packageParams.put("contact", name); // 联系人
		packageParams.put("contact_phone", WxRSAEncrypt.rsaEncrypt(mobileNo));
		
		String sign = PayCommonUtil.createSign4HMAC("UTF-8", packageParams, AES_KEY);

		packageParams.put("sign", sign);

		String requestXML = PayCommonUtil.getRequestXml(packageParams);
		System.out.println(requestXML);
		//得到含有prepay_id的XML
		String resXml = HttpUtil.postData("https://api.mch.weixin.qq.com/applyment/micro/submit", requestXML, MCH_ID, CERT_PATH);
		//解析XML存入Map
		Map map = XMLUtil.doXMLParse(resXml);
		System.out.println(map);
		return map;
	}
	
	/**
	 * 获取平台证书
	 * 
	 * @return
	 */
	public static String getCertficates() {
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		packageParams.put("mch_id", MCH_ID);
		packageParams.put("nonce_str", System.currentTimeMillis() + "");
		packageParams.put("sign_type", "HMAC-SHA256");
		String sign = PayCommonUtil.createSign4HMAC("UTF-8", packageParams, AES_KEY);

		packageParams.put("sign", sign);

		String requestXML = PayCommonUtil.getRequestXml(packageParams);
		System.out.println(requestXML);
		// 得到含有prepay_id的XML
		String resXml = HttpUtil.postData("https://api.mch.weixin.qq.com/risk/getcertficates", requestXML);
		System.out.println(resXml);
		return "";
	}

	/**
	 * 解密证书
	 * 
	 * @param aad
	 * @param iv
	 * @param cipherText
	 * @return
	 * @throws Exception
	 */
	private static String aesgcmDecrypt(String aad, String iv, String cipherText) throws Exception {
		final Cipher cipher = Cipher.getInstance(ALGORITHM, "SunJCE");
		SecretKeySpec key = new SecretKeySpec(AES_KEY.getBytes(), "AES");
		GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, iv.getBytes());
		cipher.init(Cipher.DECRYPT_MODE, key, spec);
		cipher.updateAAD(aad.getBytes());
		return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)));
	}

}
