package com.yc.ship.module.trade.framework.common.ota;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;

/**
 * @Title: USGroupAuthUtils.java
 * @Package: com.wisesoft.scenic.util
 * &#064;Description: 美团BA认证工具类
 * @date: 2017年5月11日 下午2:28:50
 * @version: V1.0
 */
public class MeiTuanUSGroupAuthUtils {
	
	private static final String ALGORITHM_HMAC_SHA1 = "HmacSHA1";
    public static final String HTTP_HEADER_PARTNERID = "PartnerId";
    public static final String HTTP_HEADER_DATE = "Date";
    public static final String HTTP_HEADER_AUTHORIZATION = "Authorization";
    public static final String MEITUAN_AUTH_METHOD = "MWS";
    private static final String HTTP_HEADER_TIME_ZONE = "GMT";
    private static final String HTTP_HEADER_DATE_FORMAT = "EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'z";

    /**
    * 生成请求头认证信息：美团标准代码
    * @param request
    * @param clientId
    * @param clientSecret
    * @param partnerId
    */
    public static Map<String, Object> generateAuthAndDateHeader(HttpServletRequest request, String clientId,
                                                                String clientSecret, String partnerId) {
    	Map<String, Object> resultMap = new HashMap<String, Object>();
        Date sysdate = new Date();
        SimpleDateFormat df = new SimpleDateFormat(HTTP_HEADER_DATE_FORMAT, Locale.US);
        df.setTimeZone(TimeZone.getTimeZone(HTTP_HEADER_TIME_ZONE));
        String date = df.format(sysdate);
        String stringToSign = request.getMethod().toUpperCase() + " " +
                                            request.getRequestURI() +
                                            "\n" + date;
        String encoding;
        try {
            encoding = encodeSignature(stringToSign.getBytes(), clientSecret.getBytes());
        } catch (Exception e1) {
            //LogUtil.appLog.warn("Signature Exception occured:", e1);
            return resultMap;
        }
        String authorization = MEITUAN_AUTH_METHOD + " " + clientId + ":" + encoding;
        resultMap.put(HTTP_HEADER_AUTHORIZATION, authorization);
        resultMap.put(HTTP_HEADER_DATE, date);
        resultMap.put(HTTP_HEADER_PARTNERID, partnerId);
        return resultMap;
    }
    
    /**
     * 校验sign前生成sign信息用于和美团sign信息比较
     * @param method
     * @param uri
     * @param clientId
     * @param clientSecret
     * @author zhoulonggui
     * @date 2017年5月15日
     */
    public static Map<String, String> generateSign(String method, String uri, String clientId,
            String clientSecret, String date) {
		Map<String, String> resultMap = new HashMap<String, String>();
		if(StringUtils.isEmpty(date)){
			Date sysdate = new Date();
			SimpleDateFormat df = new SimpleDateFormat(HTTP_HEADER_DATE_FORMAT, Locale.US);
			df.setTimeZone(TimeZone.getTimeZone(HTTP_HEADER_TIME_ZONE));
			date = df.format(sysdate);
		}
		String stringToSign = method.toUpperCase() + " " + uri + "\n" + date;
		//LogUtil.appLog.info("stringToSign:" + stringToSign);
		//LogUtil.appLog.info("date:"+date);
		String encoding;
		try {
			encoding = encodeSignature(stringToSign.getBytes(), clientSecret.getBytes());
		} catch (Exception e1) {
			//LogUtil.appLog.warn("Signature Exception occured:", e1);
			return resultMap;
		}
		String authorization = MEITUAN_AUTH_METHOD + " " + clientId + ":" + encoding;
		//LogUtil.appLog.info(authorization);
		//LogUtil.appLog.info("美团认证：authorization:" + authorization);
		resultMap.put(HTTP_HEADER_AUTHORIZATION, authorization);
		resultMap.put(HTTP_HEADER_DATE, date);
		return resultMap;
	}

    /**
    * 生产签名：美团标准代码
    * @param data
    * @param key
    * @return
    * @throws InvalidKeyException
    * @throws NoSuchAlgorithmException
    */
    public static String encodeSignature(byte[] data, byte[] key)
                                            throws InvalidKeyException,NoSuchAlgorithmException {
        SecretKeySpec signingKey = new SecretKeySpec(key, ALGORITHM_HMAC_SHA1);
        Mac mac = Mac.getInstance(ALGORITHM_HMAC_SHA1);
        mac.init(signingKey);
        byte[] rawHmac = mac.doFinal(data);
        return new String(Base64.encodeBase64(rawHmac));
    }
    
    /**
     * 美团标准代码
     * @param data
     * @param key
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @author zhoulonggui
     * @date 2017年8月23日
     */
    public static String decodeSignature(byte[] data, byte[] key)
            throws InvalidKeyException,NoSuchAlgorithmException {
		SecretKeySpec signingKey = new SecretKeySpec(key, ALGORITHM_HMAC_SHA1);
		Mac mac = Mac.getInstance(ALGORITHM_HMAC_SHA1);
		mac.init(signingKey);
		byte[] rawHmac = mac.doFinal(data);
		return new String(Base64.decodeBase64(rawHmac));
	}
	
    /**
     * 校验签名
     * @param request
     * @param userId
     * @param userKey
     * @throws Exception
     * return
     * @author zhoulonggui
     * @date 2017年8月23日
     */
    public static boolean checkSign(HttpServletRequest request, String userId, String userKey) throws Exception {
    	try {
    		String uri = request.getRequestURI();
    		String date = request.getHeader(HTTP_HEADER_DATE);
    		Map<String, String> checkMap = generateSign("POST", uri, userId, userKey, date);
    		String authSign = "";
    		if(null != checkMap){
    			String key = "";
    			String value = "";
    			for(Entry<String, String> map : checkMap.entrySet()){
    				key = map.getKey();
    				value = map.getValue();
    				//System.out.println("key:"+key+",value:"+value);
    				if(MeiTuanUSGroupAuthUtils.HTTP_HEADER_AUTHORIZATION.equalsIgnoreCase(key)){
    					authSign = value;
    				}
    			}
    		}
    		String oldSign = request.getHeader(MeiTuanUSGroupAuthUtils.HTTP_HEADER_AUTHORIZATION);
    		//LogUtil.appLog.info("美团签名auth："+oldSign);
    		//LogUtil.appLog.info("美团签名date："+date);
    		//LogUtil.appLog.info("我方auth："+authSign);
    		if(authSign.equals(oldSign)){
    			//LogUtil.appLog.info("美团：sign签名校验成功");
    			return true;
    		}

		} catch (Exception e) {
			//LogUtil.appLog.error("美团：sign签名校验异常");
			throw new Exception("校验签名失败");
		}
		return false;
	}
    
    @SuppressWarnings("rawtypes")
	public static Map<String, String> getHeadersInfo(HttpServletRequest request) {
        Map<String, String> map = new HashMap<String, String>();
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
            //LogUtil.appLog.info("key:" + key + ",value:" + value);
        }
        return map;
      }
    
    public static void main(String[] args) {
    	//POST /rhone/lv/deal/change/notice"+"\n"+"Wed, 06 May 2015 10:34:20 GMT
    	String uri = "/rhone/lv/deal/change/notice";
    	String method = "POST";
    	//generateSign(method, uri, "lvyou_347", "123456ce8b61f8e608eaf2e9702864a9");
	}
    
}
