package cn.pluss.platform.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;

import org.apache.commons.codec.binary.Hex;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class WeChatImageUploadUtils {
	private static String keyStoreUrl = "/home/syb/resources/wechatCert/apiclient_cert.p12";
	private static String requestUrl = "https://api.mch.weixin.qq.com/secapi/mch/uploadmedia";
	private static String payKey = "7F05NZBTJ3XNDK5HLSDC3H25ZXOQKDHT";
	private static String mch_id = "1551169371";

	// 获取微信商家进价上传图片的mediaId
	public static String upload(File file) {
		String mediaId = null;
		try {
			String media_hash = md5HashCode(new FileInputStream(file));
			String sign_type = "HMAC-SHA256";
			Map<String, Object> paramMap = new HashMap<>();
			paramMap.put("mch_id", mch_id);
			paramMap.put("media_hash", media_hash);
			paramMap.put("sign_type", sign_type);
			String sign = sha256Sign(paramMap, payKey);

			MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
			multipartEntityBuilder.addTextBody("mch_id", mch_id, ContentType.MULTIPART_FORM_DATA);
			multipartEntityBuilder.addBinaryBody("media", file, ContentType.create("image/jpg"), file.getName());
			multipartEntityBuilder.addTextBody("media_hash", media_hash, ContentType.MULTIPART_FORM_DATA);
			multipartEntityBuilder.addTextBody("sign_type", sign_type, ContentType.MULTIPART_FORM_DATA);
			multipartEntityBuilder.addTextBody("sign", sign, ContentType.MULTIPART_FORM_DATA);
			FileInputStream instream = null;
			SSLContext sslcontext = null;
			try {
				KeyStore keyStore = KeyStore.getInstance("PKCS12");
				Properties prop = System.getProperties();
		        String os = prop.getProperty("os.name");
		        if(os.startsWith("win") || os.startsWith("Win")){
		        	//windows目录
		        	keyStoreUrl="D:\\Dev\\SVN\\Java\\pluss\\shoyinbei\\pluss-common-bundle\\src\\main\\resources\\apiclient_cert.p12";
		        }
				instream = new FileInputStream(new File(keyStoreUrl));
				keyStore.load(instream, mch_id.toCharArray());// 这里写密码..默认是你的MCHID
				sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
			} catch (Exception e) {
				System.out.println(e.getMessage());
			} finally {
				try {
					if (instream != null) {
						instream.close();
					}
				} catch (IOException e) {

				}
			}
			@SuppressWarnings("deprecation")
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" },
					null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
			CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			try {
				HttpPost httpPost = new HttpPost(requestUrl);
				RequestConfig config = RequestConfig.custom().setConnectTimeout(10000)
						.setConnectionRequestTimeout(10000).setSocketTimeout(10000).build();
				httpPost.setConfig(config);
				//// 这里的Content-type要设置为"multipart/form-data"，否则返回“参数填写有误，请检查后重试”
				httpPost.addHeader(HTTP.CONTENT_TYPE, "multipart/form-data; charset=UTF-8");
				httpPost.addHeader(HTTP.USER_AGENT, "wxpay sdk java v1.0 " + mch_id);
				httpPost.setEntity(multipartEntityBuilder.build());
				CloseableHttpResponse response = httpclient.execute(httpPost);
				String result = EntityUtils.toString(response.getEntity(), "UTF-8");

				Document document = null;

				Document doc = null;
				try {
					doc = DocumentHelper.parseText(result);
				} catch (DocumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				Element root = doc.getRootElement();
				String return_code = root.element("return_code").getTextTrim();

				if ("SUCCESS".equalsIgnoreCase(return_code)) {

					mediaId = root.element("media_id").getTextTrim();
				}
				// System.out.println(result);
			} catch (Exception e) {

			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return mediaId;
	}

	/**
	 * 对上次文件进行MD5获取其Hash值
	 *
	 * @param fis
	 * @return
	 */
	public static String md5HashCode(InputStream fis) {
		try {
			MessageDigest MD5 = MessageDigest.getInstance("MD5");
			byte[] buffer = new byte[8192];
			int length;
			while ((length = fis.read(buffer)) != -1) {
				MD5.update(buffer, 0, length);
			}
			return new String(Hex.encodeHex(MD5.digest()));
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 获取HMAC-SHA256签名
	 *
	 * @param paramMap 签名参数（sign不参与签名）
	 * @param key      签名密钥
	 * @return HMAC-SHA256签名结果
	 */
	public final static String sha256Sign(Map<String, Object> paramMap, String key) {
		try {
			String payParam = getSignTemp(paramMap, key);
			Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
			SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
			sha256_HMAC.init(secret_key);
			byte[] array = sha256_HMAC.doFinal(payParam.getBytes("UTF-8"));
			StringBuilder sb = new StringBuilder();
			for (byte item : array) {
				sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
			}
			String sign = sb.toString().toUpperCase();
			return sign;
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 获取签名参数字符串
	 *
	 * @param paramMap 签名参数（sign字段不参与签名）
	 * @param payKey   签名密钥
	 * @return 待签名字符串
	 */
	private final static String getSignTemp(Map<String, Object> paramMap, String payKey) {
		ArrayList<String> keyList = new ArrayList<>(paramMap.keySet());
		Collections.sort(keyList);

		StringBuilder signParam = new StringBuilder();
		for (String key : keyList) {
			if (!"sign".equals(key) && !StringUtil.isEmpty(paramMap.get(key).toString())) {
				signParam.append(key).append("=").append(paramMap.get(key)).append("&");
			}
		}
		signParam.delete(signParam.length() - 1, signParam.length());
		signParam.append("&key=").append(payKey);
		return signParam.toString();
	}

}
