package com.rrtx.services.pay.weixin;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
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 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.conn.ssl.SSLContexts;
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.util.EntityUtils;
import org.aspectj.util.FileUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.min.util.CommonUtil;

public class WxUploadFile {
	
	public static final int BYTESIZE = 1024;                                        //每次读取的大小 1KB
	
	private static final Logger logger = LoggerFactory
			.getLogger(WxUploadFile.class);

	public static void main(String[] args) {
		File file = new File("C:\\Users\\zhangzz\\Desktop\\liumm\\sbzfm.png");
//		upload(file, "1530165211", "D:\\temp\\1530165211_20190328_cert\\apiclient_cert.p12",
//				"https://api.mch.weixin.qq.com/secapi/mch/uploadmedia",
//				"aNeIu3mTcUF0iEMsyOg2iici1FLxGjWU");
	}

	/**
     * 将文件流保存在项目WEB-INF/temp目录下，并且返回这个文件；
     * @param is              待转化的文件流
     * @param fileName        临时文件名
     * @return
     * @throws IOException
     */
    public static File saveTempFile(InputStream is, String fileName){
        String path = "";
        try {
            path = URLDecoder.decode(FileUtil.class.getClassLoader().getResource("").getPath(), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        System.out.println(path);
        
        File temp = new File(path + fileName);
        
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try{
            bis = new BufferedInputStream(is);
            bos = new BufferedOutputStream(new FileOutputStream(temp));                            //把文件流转为文件，保存在临时目录
            int len = 0;
            byte[] buf = new byte[10 * BYTESIZE];                                                    //缓冲区
            while((len=bis.read(buf)) != -1){
                bos.write(buf, 0, len);
            }
            bos.flush();
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            try {
                if(bos!=null) bos.close();
                if(bis!=null) bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return temp;
    }
    
	/**
	 * 真实上传方法
	 * 
	 * @param file
	 * @param mch_id
	 * @param keyStoreUrl
	 * @param requestUrl
	 * @param payKey
	 */
	public static String upload(String urlFilePath, String mch_id, String keyStoreUrl, String requestUrl, String payKey) {

	        try {
	        	File file = saveTempFile(HttpUtil.urlToInputStream(urlFilePath), "uplaodTemp.jpg");
	            String media_hash = md5HashCode(new FileInputStream(file));
	            String sign_type = "HMAC-SHA256";
	            Map<String, Object> paramMap = new HashMap<String, Object>();
	            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"), "3_cover_chan.jpg");
	            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");
	                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) {
	                logger.error("官方微信--证书加载失败!{}", e);
	            } finally {
	                try {
	                    if (instream != null) {
	                        instream.close();
	                    }
	                } catch (IOException e) {
	                    logger.error("官方微信--证书加载失败!{}", 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");
	                logger.info("官方微信--请求返回结果：{}", result);
	                return result;
	            } catch (Exception e) {
	                logger.error("官方微信--请求失败！{}", e);
	            }


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

	/**
	 * 对上次文件进行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);
			logger.info("签名原文:{}", payParam);
			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();
			logger.info("签名结果:{}", sign);
			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<String>(paramMap.keySet());
	        Collections.sort(keyList);

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