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

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.net.ssl.SSLContext;

import com.upyuns.platform.rs.universal.weixin.util.WeChatSignUtil;
import com.upyuns.platform.rs.universal.weixin.util.XmlUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

/**
 * 微信支付退款工具类(先测试双向证书退款功能是否能正常，如果能正常再接入正常业务)
 * 
 * @author hezhen
 *
 */
@Slf4j
public class WxPayRefundUtils {
	private static final String URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
	// private static final String pay_appId = "wx81470220f10b266e";
	// private static final String pay_mchId = "1423414902";
	// private static final String subMchId = "1511773781";
	//private static final String APICLIENT_CERT = SystemConfig.APICLIENT_CERT;
	// private static final String pay_partnerKey =
	// "CNITR89201000CNITR89201000FUWUSH";

	public static boolean refund(String pay_appId, String pay_mchId,String pay_partnerKey,
			String out_trade_no,String out_refund_no, String total_fee, String refund_fee, String refund_desc,String apiclient_cert) {
		String result = postXML(URL, genXML(pay_appId, pay_mchId,pay_partnerKey, out_trade_no,out_refund_no, total_fee,
				refund_fee, refund_desc), pay_mchId,apiclient_cert);
		log.info(result);
		// 判定退款操作结果是否正确
		String return_msg = "<return_msg><![CDATA[OK]]></return_msg>";
		String result_code = "<result_code><![CDATA[SUCCESS]]></result_code>";
		String return_code = "<return_code><![CDATA[SUCCESS]]></return_code>";
		return result.contains(result_code) && result.contains(return_msg) && result.contains(return_code);
	}

	private static String postXML(String url, String xml, String pay_mchId,String apiclient_cert) {
		try (FileInputStream ips = new FileInputStream(new File(apiclient_cert));) {
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			keyStore.load(ips, pay_mchId.toCharArray());
			SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, pay_mchId.toCharArray()).build();
			@SuppressWarnings("deprecation")
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1" },
					null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
			CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			return post(httpClient, url, xml, "text/xml; charset=UTF-8", "UTF-8", null, null);
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		return null;
	}

	private static String post(CloseableHttpClient httpclient, String uri, String data, String miniType, String charset,
			String cookie, String refer) {
		HttpPost httpPost = new HttpPost(uri);
		if (miniType != null) {
			httpPost.setHeader("Content-Type", miniType);
		}

		if (data != null) {
			StringEntity stringEntity = null;
			try {
				if (charset != null) {
					stringEntity = new StringEntity(data, charset);
				} else {
					stringEntity = new StringEntity(data);
				}
			} catch (Exception e) {
				log.error(e.getMessage(), e);;
				return "failure";
			}

			httpPost.setEntity(stringEntity);
		}
		if (cookie != null) {
			httpPost.setHeader("Cookie", cookie);
		}
		if (refer != null) {
			httpPost.setHeader("Refer", refer);
		}

		CloseableHttpResponse httpResponse = null;
		HttpContext httContext = HttpClientContext.create();
		try {
			httpResponse = httpclient.execute(httpPost, httContext);
		} catch (Exception e) {
			log.error(e.getMessage(), e);;
			return "failure";
		}

		HttpEntity httpEntity = null;
		try {
			httpEntity = httpResponse.getEntity();
		} catch (Exception e) {
			log.error(e.getMessage(), e);;
			return "failure";
		}

		String response_body = null;
		try {
			response_body = EntityUtils.toString(httpEntity, "utf-8");
		} catch (Exception e) {
			log.error(e.getMessage(), e);;
			return "failure";
		}

		try {
			httpResponse.close();
		} catch (Exception e) {
			log.error(e.getMessage(), e);;
		}
		try {
			httpclient.close();
		} catch (Exception e) {
			log.error(e.getMessage(), e);;
		}

		return response_body;
	}

	private static String genXML(String pay_appId, String pay_mchId, String pay_partnerKey,
			String out_trade_no,String out_refund_no, String total_fee, String refund_fee, String refund_desc) {
		Random random = new Random();
		long nextLong = random.nextLong();
		String nonce_str = nextLong + "";
		String sign = genSign(pay_appId, pay_mchId, pay_partnerKey, out_trade_no, total_fee, refund_fee,
				out_refund_no, refund_desc, nonce_str);
		XMLTempBean xmlTempBean = new XMLTempBean(pay_appId, pay_mchId, nonce_str, out_trade_no, total_fee,
				refund_fee, out_refund_no, refund_desc, sign);
		String xml = XmlUtils.toXml("xml", XMLTempBean.class, xmlTempBean);
		log.info("genXML:"+xml);
		return xml;
	}

	private static String genSign(String pay_appId, String pay_mchId, String pay_partnerKey,
			String out_trade_no, String total_fee, String refund_fee, String out_refund_no, String refund_desc,
			String nonce_str) {
		Map<String, String> map = new HashMap<String, String>();
		map.put("appid", pay_appId);
		map.put("mch_id", pay_mchId);
		map.put("nonce_str", nonce_str);
		map.put("out_trade_no", out_trade_no);
		map.put("total_fee", total_fee);
		map.put("refund_fee", refund_fee);
		map.put("out_refund_no", out_refund_no);
		map.put("refund_desc", refund_desc);
		String sign = WeChatSignUtil.getMD5Sign(map, pay_partnerKey);
		return sign;
	}
}

class XMLTempBean {
	private String appid;
	private String mch_id;
	private String nonce_str;
	private String out_trade_no;
	private String total_fee;
	private String refund_fee;
	private String refund_desc;
	private String out_refund_no;
	private String sign;

	public XMLTempBean(String appid, String mch_id, String nonce_str, String out_trade_no,
			String total_fee, String refund_fee, String out_refund_no, String refund_desc, String sign) {
		super();
		this.appid = appid;
		this.mch_id = mch_id;
		this.nonce_str = nonce_str;
		this.out_trade_no = out_trade_no;
		this.total_fee = total_fee;
		this.refund_fee = refund_fee;
		this.refund_desc = refund_desc;
		this.out_refund_no = out_refund_no;
		this.sign = sign;
	}

	public String getAppid() {
		return appid;
	}

	public String getMch_id() {
		return mch_id;
	}

	public String getNonce_str() {
		return nonce_str;
	}

	public String getOut_trade_no() {
		return out_trade_no;
	}

	public String getTotal_fee() {
		return total_fee;
	}

	public String getRefund_desc() {
		return refund_desc;
	}

	public String getSign() {
		return sign;
	}

	public String getOut_refund_no() {
		return out_refund_no;
	}

	public String getRefund_fee() {
		return refund_fee;
	}

}
