package com.younike.common.utils.jwt;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.MACSigner;
import com.younike.common.utils.date.DateUtils;
import org.apache.commons.lang.StringUtils;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtil {

	private static final String SECRI = "0002000200020002";
	
	public static void main(String[] args) throws Exception {
		// 生成网站token
		String token = generateWebToken("1#@lutf@pgy.space");

		// 验证网站token
		// boolean active = validateWebToken(token);
		System.out.println("***" + getWebToken(token));
	}
	
	/**
	 * 
	 * @param UserId
	 * @return
	 * @throws JOSEException
	 * @throws ParseException
	 * eg
	 * eyJhbGciOiJIUzI1NiJ9.ewoJInRpbWVTdGFtcCI6IkEzMERGNTQxMkM0NEZDRTRDMTE1QzBBRUJGRjFGNzhCRjZFQzEyODI5MjkyNDZFRCIsCgkidG9rZW4iOiI4OTAyODE5NTE4REM2NTlCIgp9.D7Pl5ulx1dWCocunnBo6bjcHjSD0Lx8zui8b4ktpo9k
	 */
	public static String generateWebToken(String UserId) throws JOSEException, ParseException{
		String token = "";
		if(StringUtils.isEmpty(UserId)){
			return "";
		}
		
		//32位 小写 RDKC
		String sharedSecret = MD5.getMD5("RDKC"); 

		// Create HMAC signer
		JWSSigner signer = new MACSigner(sharedSecret);

		// Prepare JWS object with "Hello, world!" payload
		Map<String, String> map = new HashMap<String, String>();
		
		String currentTim = DateUtils.dateToString(DateUtils.PATTEN_FILE_RENAME);
		String secriUserid = GenPass.Encrypt(UserId, hex2byte(SECRI));
		String secriCirrentTime = GenPass.Encrypt(currentTim, hex2byte(SECRI));
		System.out.println("secriUserid: " + secriUserid);
		System.out.println("secriCirrentTime: " + secriCirrentTime);
		map.put("token", secriUserid);
		map.put("timeStamp", secriCirrentTime);
		String json = JSON.toJSONString(map, true);
		JWSObject jwsObject = new JWSObject(new JWSHeader(JWSAlgorithm.HS256), new Payload(json));

		// Apply the HMAC
		jwsObject.sign(signer);

		// To serialize to compact form, produces something like
		// eyJhbGciOiJIUzI1NiJ9.SGVsbG8sIHdvcmxkIQ.onO9Ihudz3WkiauDO2Uhyuz0Y18UASXlSc1eS0NkWyA
		token = jwsObject.serialize();
				System.out.println(token);
		return token;
	}
	
	/**
	 * 
	 * @param jwtToken 前端直接传回的加密的 token信息
	 * @return 验证时间是否在有效时间内
	 * @throws Exception 
	 * 
	 */
	public static boolean validateWebToken(String jwtToken) throws Exception{
		String webToken = getWebTokenContent(jwtToken);
		
		return validateUsrToken(webToken);
	}
	

    /**
	 * 
	 * @param jwtToken 前端直接传回的加密的 token信息
	 * @return 解密后字符
	 * @throws Exception
	 */
    public static String getWebToken(String jwtToken) throws Exception{
        String webToken = getWebTokenContent(jwtToken);
        Map<String, String> map = getUsrTokenContent(webToken);
        return map.get("token");
    }

    /**
     * 
     * @param jwtToken 前端直接传回的加密的 token信息
     * @return 解密后字符
     * @throws Exception
     */
    public static Map<String, String> getWebTokenForMap(String jwtToken) throws Exception{
        String webToken = getWebTokenContent(jwtToken);
        return getUsrTokenContent(webToken);
    }
	
	public static String getWebTokenContent(String jwtToken) throws JOSEException, ParseException{

		//32位 小写 RDKC
		String sharedSecret = MD5.getMD5("RDKC"); 

		// Create HMAC signer
		JWSSigner signer = new MACSigner(sharedSecret);

		// Prepare JWS object with "Hello, world!" payload
		JWSObject jwsObject = new JWSObject(new JWSHeader(JWSAlgorithm.HS256), new Payload(""));

		// Apply the HMAC
		jwsObject.sign(signer);

		// To serialize to compact form, produces something like
		// To parse the JWS and verify it, e.g. on client-side
		jwsObject = JWSObject.parse(jwtToken);

		return jwsObject.getPayload().toString();
	}
	
	/**
	 * 
	 * @param usrToken
	 * @return
	 * @throws Exception 
	 */
	public static boolean validateUsrToken(String usrToken) throws Exception{
		boolean result = false;
		
		if(StringUtils.isNotEmpty(usrToken)){
			Map<String, String> map = getUsrTokenContent(usrToken);
			if(map != null && map.containsKey("timeStamp")){
				String timeStamp = map.get("timeStamp");
				Date loginDate = DateUtils.stringToDate(timeStamp, DateUtils.PATTEN_FILE_RENAME);
				
				//计算相差的时间差
				long nd = 1000 * 60 * 60;// 一小时的毫秒数
				long diff = 0;
				// 获得两个时间的毫秒时间差异
				diff = new Date().getTime() - loginDate.getTime();
				long day = diff / nd;// 计算差多少小时
				int date = new Long(day).intValue();
				
				if(date < 1440){
					result = true;
				}
			}
		}
		return result;
	}
	
	public static Map<String, String> getUsrTokenContent(String usrToken) throws JOSEException, ParseException{
		Map<String, String> map = new HashMap<String, String>();
		String secriUserid = "";
		String secriCirrentTime = "";
		
		if(StringUtils.isNotEmpty(usrToken)){
			JSONObject json = (JSONObject) JSONObject.parse(usrToken);
			String token = (String) json.get("token");
			String timeStamp = (String) json.get("timeStamp");
			System.out.println("token: " + token);
			System.out.println("timeStamp: " + timeStamp);
			secriUserid = GenPass.Decrypt(token, hex2byte(SECRI)) ;
			secriCirrentTime = GenPass.Decrypt(timeStamp, hex2byte(SECRI));
			
			map.put("token", secriUserid);
			map.put("timeStamp", secriCirrentTime);
			
		}
		return map;
	}
	
	public static byte[] hex2byte(String hex) throws IllegalArgumentException {
		if (hex.length() % 2 != 0) {
			throw new IllegalArgumentException();
		}
		char[] arr = hex.toCharArray();
		byte[] b = new byte[hex.length() / 2];
		for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
			String swap = "" + arr[i++] + arr[i];
			int byteint = Integer.parseInt(swap, 16) & 0xFF;
			b[j] = new Integer(byteint).byteValue();
		}
		return b;
	}
	
	public static String getUsrIdFromWebToken(String jwtToken) throws JOSEException, ParseException {
		JWSObject jwsObject = JWSObject.parse(jwtToken);
		String payload = jwsObject.getPayload().toString();
		
		if(StringUtils.isNotEmpty(payload)){
			Map<String, String> map = getUsrTokenContent(payload);
			if(map != null && map.containsKey("token")){
				String secriUserid = map.get("token");
				return secriUserid;
			}
		}
		
		return null;
	}

}
