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

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.neusoft.smart.pos.framework.constants.ApplicationConstants;
import lombok.val;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

public class SignUtils {

	/**
	 * 签名生成使用方法
	 * @param param:生成签名参数
	 * @param key:生成签名使用key
	 * @return
	 */
	public static String generateSign(final Map<String,?> param, String key, String alg) {
		Set<String> keySet = param.keySet();
		String[] keyArray = keySet.toArray(new String[keySet.size()]);
		Arrays.sort(keyArray);	//对key值进行排序
		StringBuilder sb = new StringBuilder();
		for (String k : keyArray) {
			if (k.equals(ApplicationConstants.KEY_SIGN)) {
				continue;
			}
			if(null == param.get(k)){
				continue;
			}
			String val = param.get(k).toString().trim();
			if (!StringUtils.isEmpty(val) && !"\"\"".equals(val) && val.length()>0) // 参数值为空，则不参与签名
				sb.append(k).append("=").append(val).append("&");
		}
		sb.append("key=").append(key);
		return HashUtils.Hash(sb.toString(), HashUtils.FMT_UTF8, alg);
	}

	public static String generateSign(final Map<String,?> param, String key) {
		val sign = generateSign(param,key, HashUtils.ALG_MD5);
		return sign;//MD5Utils.MD5(sign);
	}

	public static String generateSignSHA256(final Map<String,?> param, String key) {
		val sign = generateSign(param,key, HashUtils.ALG_SHA256);
		return HashUtils.SHA256(sign);
	}

	public static <T>  String generateSign(T bean, String key, String alg) {
		final Map<String,?> param = beanToMap(bean);
		return generateSign(param, key, alg);
	}

	public static <T>  boolean isSignatureValid(T bean, String key,  String alg) {
		boolean flag = false;
		final Map<String,?> param = beanToMap(bean);
		String sign = generateSign(param, key, alg);
		if(null != sign && sign.equalsIgnoreCase(param.get(ApplicationConstants.KEY_SIGN).toString())){
			flag = true;
		}
		return flag;
	}

	public static <T>  boolean isSignatureValid(T bean, String key) {
		return isSignatureValid(bean, key, HashUtils.ALG_MD5);
	}
	public static <T>  boolean isSignatureValidSHA256(T bean) {
		return isSignatureValid(bean, IdGenerateUtils.STATIC_SIGN_KEY, HashUtils.ALG_SHA256);
	}

	public static <T>  boolean isSignatureValidSHA256(T bean, String key) {
		return isSignatureValid(bean, key, HashUtils.ALG_SHA256);
	}

	private static Gson mGson = new Gson();

	private static String fillStartEnd(String data){
		String ret = data;
		if(!ret.startsWith("\"")) {
			data = "\"" + data;
		}

		if(!ret.endsWith("\"")) {
			data = data + "\"";
		}

		return ret;
	}

	public static <T> Map<String, String> beanToMap(T bean) {
		Map<String, String> map = new HashMap<>();
		if (bean != null) {

			JsonElement jsonElementBean = mGson.toJsonTree(bean);

			if(jsonElementBean.isJsonObject()) {
				JsonObject json = jsonElementBean.getAsJsonObject();
				for(String key: json.keySet()) {
					JsonElement val = json.get(key);

					if(val.isJsonPrimitive()) {
						map.put(key, fillStartEnd(val.getAsString()));
					}else if (val.isJsonNull()) {
						map.put(key, "");
					} else {
						// val.isJsonArray() || val.isJsonObject() || other
						continue;
					}
				}
			}
		}
		return map;
	}


    public static String buildUrlParametersStr(LinkedHashMap<String, String> paramMap) {
        StringBuffer buffer = new StringBuffer();
        for (Map.Entry<String, String> entry : paramMap.entrySet()) {
            buffer.append(entry.getKey()).append("=");
            try {
                if (entry.getValue() != null && !StringUtils.isEmpty(entry.getValue())) {
                    buffer.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
                }
            } catch (UnsupportedEncodingException e) {
            }
            buffer.append("&");
        }

        if('&' == buffer.charAt(buffer.length() - 1)) {
            buffer.deleteCharAt(buffer.length() - 1);
        }

        return buffer.toString();
    }

}
