package com.neusoft.smart.pos.payment.utils;

import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.util.Base64Utils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.Map.Entry;


/**
 * 格式化工具类
 * @author HP
 *
 */
public class XYHYFormatUtils {
	private final static Logger log = Logger.getLogger(XYHYFormatUtils.class);

	/**
	 * 根据私钥加密消息字符串
	 * @param secretkey
	 * @param privateKey
	 * @param jsonString
	 * @return
	 */
	public static String encryptMessageByPrivateKey(String secretkey,String privateKey,String jsonString){
		log.info("加密开始.....");
		log.info("加密商户的秘钥为 "+secretkey+" ,私钥为 "+privateKey+" ,传入用户数据为 "+jsonString);
		String formatString = formatInputJson(jsonString);
		try {
			String hmac = HMACSHA256(formatString.getBytes("UTF-8"),secretkey.getBytes("UTF-8"));
			log.info("HMACSHA256加密拼接字符串： "+hmac);
			byte[] encodedData = XYHFRSAUtils.encryptByPrivateKey(hmac.getBytes(), privateKey);
			String encryptMessage = new String(Base64Utils.encode(encodedData));
			log.info("加密成功，加密结果为 "+encryptMessage);
			JSONObject resultJsonObject = new JSONObject(jsonString);
			resultJsonObject.put("SIGNATURE", encryptMessage);
			String resultString = resultJsonObject.toString();
			log.info("发送给西银惠付的消息为" +resultString);
			return resultString;
		} catch (UnsupportedEncodingException e) {
			log.error("HMACSHA256加密失败！",e);
		} catch (Exception e) {
			log.error("加密失败...",e);
		}
		return "";
	}


	/**
	 * 格式化拼接传过来的字符
	 * @param inputString
	 * @return
	 */
	public static String formatInputJson(String inputString){
		StringBuffer sb = new StringBuffer();
		JSONObject json = null;
		try {
			json = new JSONObject(inputString);
			Iterator<?> iteratorKeys = json.keys();//得到所有title  
			
			SortedMap<String, String> map = new TreeMap<String, String>();  
			while (iteratorKeys.hasNext()) {  
				String key = iteratorKeys.next().toString();  
				String value = json.optString(key);
				if(null != value && !"".equals(value) && !"null".equals(value)){
					map.put(key, value);  
				}
			}  
			for (Entry<String, String> string : map.entrySet()) {
				sb.append(string.getKey()+"=");
				sb.append(string.getValue()+"&");
			}
			String resultTemp = sb.toString();
			String result = resultTemp.substring(0,resultTemp.length()-1);
			log.info("拼接明文："+result);
			return result;
		} catch (JSONException e) {
			log.error("json格式不正确",e);
			log.error("拼接明文失败",e);
		}
		return "";
	}
	
	/**
	 * HMACSHA256加密算法
	 * @param data
	 * @param key
	 * @return
	 */
	public static String HMACSHA256(byte[] data, byte[] key) 
	{
	      try  {
	         SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA256");
	         Mac mac = Mac.getInstance("HmacSHA256");
	         mac.init(signingKey);
	         return byte2hex(mac.doFinal(data));
	      } catch (NoSuchAlgorithmException e) {
	         e.printStackTrace();
	      } catch (InvalidKeyException e) {
	        e.printStackTrace();
	      }
	      return null;
	} 
	public static String byte2hex(byte[] b) 
	{
	    StringBuilder hs = new StringBuilder();
	    String stmp;
	    for (int n = 0; b!=null && n < b.length; n++) {
	        stmp = Integer.toHexString(b[n] & 0XFF);
	        if (stmp.length() == 1)
	            hs.append('0');
	        hs.append(stmp);
	    }
	    return hs.toString();
	}
	
	/**
	 * 校验传输的格式是否正确
	 * @return
	 */
	public static boolean formatCorrect(String ... args){
		boolean flag = true;
		for (String string : args) {
			if(stringIsNull(string)){
				return flag;
			}
		}
		flag = false;
		return flag;
	}
	
	/**
	 * 判断字符串是否为空
	 * @param str
	 * @return
	 */
	public static boolean stringIsNull(String str){
		if(null == str || "".equals(str)){
			log.error("参数为空...");
			return true;
		}
		return false;
	}
	
	
	/**
	 * 将byte[]转成utf-8格式的String
	 * 
	 * @param inputData
	 * @return
	 */
	public static String byteToString(byte[] inputData) {
		try {
			if (null == inputData) {
				return null;
			}
			return new String(inputData, "utf-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 处理返回消息
	 * @param privateKey
	 * @param returnMessage
	 * @return
	 */
	public static Map<String,String> handleReturnMessage(String secretkey,String privateKey,String returnMessage){
		JSONObject jsonObject = null;
		Map<String,String> resultMap = new LinkedHashMap<String, String>();
		try {
			jsonObject = new JSONObject(returnMessage);
			String encryptMessageTemp = jsonObject.getString("SIGNATURE");
			String signature = decryptOpenFlatMessage(privateKey, encryptMessageTemp);
			//去除SIGNATURE进行加密校验
			jsonObject.remove("SIGNATURE");
			String formatString = formatInputJson(jsonObject.toString());
			String hmac = HMACSHA256(formatString.getBytes("UTF-8"),secretkey.getBytes("UTF-8"));
			log.info("接收消息明文加密为 "+hmac);
			//解密签名与明文json加密后的字符串对比
			if(hmac.equalsIgnoreCase(signature)){
				log.info("校验签名成功");
				resultMap.put(XYHFMessageErrorCode.RESPONSE_MESSAGE_SUCCESS, jsonObject.toString());
				return resultMap;
			}else{
				log.info("校验签名失败");
				resultMap.put(XYHFMessageErrorCode.RESPONSE_MESSAGE_ERROE, XYHFMessageErrorCode.RESPONSE_MESSAGE_DECRYPT_ERROR);
				return resultMap;
			}
		} catch (JSONException e) {
			log.error("解析信息有错误",e);
			resultMap.put(XYHFMessageErrorCode.RESPONSE_MESSAGE_ERROE, XYHFMessageErrorCode.RESPONSE_MESSAGE_FORMAT_ERROR);
			return resultMap;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return resultMap;
	}

	/**
	 * 用私钥解密签名
	 * @param privateKey
	 * @param encryptMessage
	 * @return
	 */
	public static String decryptOpenFlatMessage(String privateKey, String encryptMessage){
		log.info("解密签名开始...");
		if(XYHYFormatUtils.formatCorrect(privateKey,encryptMessage)){
			return XYHFMessageErrorCode.REQUEST_MESSAGE_FORMAT_ERROR;
		}
		String signatureStr="";
		try {
			signatureStr = XYHYFormatUtils.byteToString(XYHFRSAUtils.decryptByPrivateKey(XYHFBase64Utils.decode(encryptMessage), privateKey));
			log.info("解密签名为 "+signatureStr);
		} catch (Exception e) {
			log.error("解密数据失败",e);
		}
		log.info("解密签名结束...");
		return signatureStr;
	}

}
