package com.bcxin.Infrastructures.utils;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.SM4;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.bcxin.Infrastructures.exceptions.BadTenantException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.Base64Utils;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtCommonUtil {

    private final static String SIGN = "dragon";
    private final static String SIGNATURE_KEY = "!@#zhian12300zhang";
    private final static String TOKEN_SECRET = "SxhlwSecurityStaff";

    /**
     * jwt秘钥 平台固定私钥
     */
    private static final String JWT_SECRET = "sdoDFyzfieqMrisd4H5o5t9weOl6GmSr";
    /**
     * SM4 平台固定私钥
     */
    private static final String SM4_KEY = "4h5o5t9weol6gmsr";
    private static final String IV = "RandomIV12345678";

    /**
     * millisecond 7天重新登录的时间间隔
     */
    private static final int JWT_REFRESH_TTL = 7*24*60*60*1000;

    /**
     * 由字符串生成加密key
     * @return
     */
    private static SecretKey generalKey(String stringKey){
        byte[] encodedKey = Base64.decodeBase64(stringKey);
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }

    /**
     * 创建jwt，ttlMillis为负数表示不过期
     * @param id
     * @param subject
     * @param ttlMillis
     * @return
     * @throws Exception
     */
    public static String createJWT(String id, String subject, String stringKey, long ttlMillis) throws Exception {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setSubject(subject)
                .signWith(signatureAlgorithm, generalKey(stringKey));
        if (ttlMillis >= 0) {
            long expMillis = System.currentTimeMillis() + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * 创建jwt
     * @param subject
     * @return
     */
    public static String createJWT(Map<String,String> subject) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        JwtBuilder builder = Jwts.builder()
//				.setId(JwtUtil.JWT_ID) // 暂时不用，减少流量
//				.setIssuedAt(new Date(System.currentTimeMillis())) //发行时间  暂时不用，减少流量
                .setSubject(JSON.toJSONString(subject)) //主题，就是附带在token中的信息
                .signWith(signatureAlgorithm, generalKey(JWT_SECRET)); //选择的算法，和私钥值
        if (JWT_REFRESH_TTL >= 0) { //如果过期时间为负数，那么不设置过期时间
            long expMillis = System.currentTimeMillis() + JWT_REFRESH_TTL;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * 创建jwt
     * @param subject
     * @return
     */
    public static String createJWT(Map<Object,Object> subject, String stringKey, long ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        JwtBuilder builder = Jwts.builder()
//				.setId(JwtUtil.JWT_ID) // 暂时不用，减少流量
//				.setIssuedAt(new Date(System.currentTimeMillis())) //发行时间  暂时不用，减少流量
                .setSubject(JSON.toJSONString(subject)) //主题，就是附带在token中的信息
                .signWith(signatureAlgorithm, generalKey(stringKey)); //选择的算法，和私钥值
        if (ttlMillis >= 0) { //如果过期时间为负数，那么不设置过期时间
            long expMillis = System.currentTimeMillis() + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * 解密jwt
     * @param jwttoken
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwttoken) {
        return Jwts.parser()
                .setSigningKey(generalKey(JWT_SECRET))
                .parseClaimsJws(jwttoken).getBody();
    }

    /**
     * 解密jwt
     */
    public static String parseJWT1(String token) {
        return Jwts.parser()
                .setSigningKey(generalKey(JWT_SECRET))
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
    }

    /**
     * 创建jwt
     *
     * @param subject
     * @return
     */
    public static String createJWT(String subject) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        JwtBuilder builder = Jwts.builder()
//				.setId(JwtUtil.JWT_ID) // 暂时不用，减少流量
//				.setIssuedAt(new Date(System.currentTimeMillis())) //发行时间  暂时不用，减少流量
                .setSubject(subject) //主题，就是附带在token中的信息
                .signWith(signatureAlgorithm, generalKey(JWT_SECRET)); //选择的算法，和私钥值
        if (JWT_REFRESH_TTL >= 0) { //如果过期时间为负数，那么不设置过期时间
            long expMillis = System.currentTimeMillis() + JWT_REFRESH_TTL;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * 验证token
     *
     * @param token 传入token
     * @return
     */
    public static Boolean validationToken(String token) {
        try {
            //设置签名的加密算法：HMAC256
            Algorithm algorithm = Algorithm.HMAC256(SIGN);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 解析token
     *
     * @param token 传入token
     * @return
     */
    public static HashMap parseToken(String token) {
        Algorithm algorithm = null;
        try {
            algorithm = Algorithm.HMAC256(SIGN);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        JWTVerifier verifier = JWT.require(algorithm).build();
        DecodedJWT jwt = verifier.verify(token);
        Map<String, Claim> claims = jwt.getClaims();
        HashMap<String, Object> result = new HashMap<>();
        result.put("koalid", claims.get("koalid").asString());// 格尔 用户id
        result.put("name", claims.get("name").asString());
        result.put("sfz", claims.get("sfz").asString());
        result.put("org", claims.get("org").asString());
        result.put("orgName", claims.get("orgName").asString());
        return result;
    }


    /**
     * <b> SM4国密解密 </b>
     * @author ZXF
     * @create 2024/05/21 0021 9:42
     * @version
     * @注意事项 </b>
     */
    public static String decryptSm4Token(String token) {
        if(StringUtils.isEmpty(token)){
            return "";
        }
        try {
            SymmetricCrypto sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, SM4_KEY.getBytes(CharsetUtil.CHARSET_UTF_8), IV.getBytes(CharsetUtil.CHARSET_UTF_8));
            byte[] cipherHex = cn.hutool.core.codec.Base64.decode(token.trim());
            return sm4.decryptStr(cipherHex,CharsetUtil.CHARSET_UTF_8);
        }catch (Exception e) {
            throw new BadTenantException("token无法识别："+e.getMessage());
        }
    }

    /**
     * <b> 北京内外单点token生成 </b>
     * @author ZXF
     * @create 2024/08/23 0023 11:21
     * @version
     * @注意事项 </b>
     */
    public static String BJZZ_createToken(Map<String, String> verifyInfoMap) {
        Algorithm SIGNATURE_ALGORITHM = null;
        try {
            SIGNATURE_ALGORITHM = Algorithm.HMAC256(SIGNATURE_KEY);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        String token = JWT.create()
                //添加头部信息
                .withHeader(map)
                //设置过期时间与签发时间
                .withExpiresAt(new Date(System.currentTimeMillis() + (15 * 24 * 60 * 60 * 1000)))
                //.withIssuedAt(new Date(System.currentTimeMillis() - preTime))
                //将基本信息放到claims中
                .withClaim("idNo", verifyInfoMap.get("idNo"))
                .withClaim("name", verifyInfoMap.get("name"))
                .withClaim("ukeySn", verifyInfoMap.get("ukeySn"))
                .withClaim("organCode", verifyInfoMap.get("organCode"))
                .withClaim("organName", verifyInfoMap.get("organName"))
                .withClaim("orgLevel", verifyInfoMap.get("orgLevel"))
                .withClaim("roleCode", verifyInfoMap.get("roleCode"))
                .withClaim("thirdLevelOrgCode", verifyInfoMap.get("thirdLevelOrgCode"))
                .withClaim("secondLevelOrgCode", verifyInfoMap.get("secondLevelOrgCode"))
                //设置摘要
                .sign(SIGNATURE_ALGORITHM);
        token = Base64Utils.encodeToString(token.getBytes(StandardCharsets.UTF_8));
        return token;
    }

    /**
     * <b> 北京内外单点token解析 </b>
     * @author ZXF
     * @create 2024/08/23 0023 11:21
     * @version
     * @注意事项 </b>
     */
    public static Map<String, String> BJZZ_verifyToken(String token) throws UnsupportedEncodingException {
        token = new String(Base64Utils.decodeFromString(token),"utf-8" );
        try {
            Algorithm  SIGNATURE_ALGORITHM = Algorithm.HMAC256(SIGNATURE_KEY);
            JWTVerifier verifier = JWT.require(SIGNATURE_ALGORITHM).build();
            DecodedJWT jwt = verifier.verify(token);
            Map<String, String> result = new HashMap<>();
            result.put("idNo", jwt.getClaim("idNo").asString());
            result.put("name", jwt.getClaim("name").asString());
            result.put("ukeySn", jwt.getClaim("ukeySn").asString());
            result.put("organCode", jwt.getClaim("organCode").asString());
            result.put("organName", jwt.getClaim("organName").asString());
            result.put("orglevel", jwt.getClaim("orglevel").asString());
            return result;
        } catch (Exception e){
            throw new BadTenantException("token无法识别："+e.getMessage());
        }
    }

    /**
     * <b> 陕西外围单点token解析 </b>
     * @author ZXF
     * @create 2024/08/23 0023 11:21
     * @version
     * @注意事项 </b>
     */
    public static Map<String, String> SXZW_verifyToken(String token){
        /**
         * @desc   验证token，通过返回true
         * @params [token]需要校验的串
         **/
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT Jwts = verifier.verify(token);
            Map<String, String> result = new HashMap<>();
            String type = Jwts.getClaim("TYPE").asString();
            result.put("TYPE", type);
            if("0".equals(type)){//自然人
                result.put("MOBILE", Jwts.getClaim("MOBILE")!=null?Jwts.getClaim("MOBILE").asString():"");
                result.put("PERSON", Jwts.getClaim("PERSON")!=null?Jwts.getClaim("PERSON").asString():"");
                result.put("PERSONID", Jwts.getClaim("PERSONID")!=null?Jwts.getClaim("PERSONID").asString():"");
            }else{//法人
                result.put("BLRMOBILE", Jwts.getClaim("BLRMOBILE")!=null?Jwts.getClaim("BLRMOBILE").asString():"");
                result.put("LEGALPERSONID", Jwts.getClaim("LEGALPERSONID")!=null?Jwts.getClaim("LEGALPERSONID").asString():"");
                result.put("LEGALPERSON", Jwts.getClaim("LEGALPERSON")!=null?Jwts.getClaim("LEGALPERSON").asString():"");
                result.put("LEGALPERSONPHONE", Jwts.getClaim("LEGALPERSONPHONE")!=null?Jwts.getClaim("LEGALPERSONPHONE").asString():"");
            }
            return result;
        }catch (Exception e){
            throw new BadTenantException("token无法识别："+e.getMessage());
        }
    }

    public static String SXZW_createToken(Map<String, String> verifyInfoMap) {
        Algorithm SIGNATURE_ALGORITHM = null;
        try {
            SIGNATURE_ALGORITHM = Algorithm.HMAC256(TOKEN_SECRET);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        String token;
        if(verifyInfoMap.get("TYPE").equals("0")){
            token = JWT.create()
                    //添加头部信息
                    .withHeader(map)
                    //设置过期时间与签发时间
                    .withExpiresAt(new Date(System.currentTimeMillis() + (15 * 24 * 60 * 60 * 1000)))
                    //.withIssuedAt(new Date(System.currentTimeMillis() - preTime))
                    //将基本信息放到claims中
                    .withClaim("MOBILE", verifyInfoMap.get("MOBILE"))
                    .withClaim("PERSON", verifyInfoMap.get("PERSON"))
                    .withClaim("PERSONID", verifyInfoMap.get("PERSONID"))
                    .withClaim("TYPE", verifyInfoMap.get("TYPE"))
                    //设置摘要
                    .sign(SIGNATURE_ALGORITHM);
        }else{
            token = JWT.create()
                    //添加头部信息
                    .withHeader(map)
                    //设置过期时间与签发时间
                    .withExpiresAt(new Date(System.currentTimeMillis() + (15 * 24 * 60 * 60 * 1000)))
                    //.withIssuedAt(new Date(System.currentTimeMillis() - preTime))
                    //将基本信息放到claims中
                    .withClaim("TYPE", verifyInfoMap.get("TYPE"))
                    .withClaim("BLRMOBILE", verifyInfoMap.get("BLRMOBILE"))
                    .withClaim("LEGALPERSONID", verifyInfoMap.get("LEGALPERSONID"))
                    .withClaim("LEGALPERSON", verifyInfoMap.get("LEGALPERSON"))
                    .withClaim("LEGALPERSONPHONE", verifyInfoMap.get("LEGALPERSONPHONE"))
                    //设置摘要
                    .sign(SIGNATURE_ALGORITHM);
        }

        return token;
    }

    /*public static void main(String[] args) throws UnsupportedEncodingException {
        Map<String, String> result = new HashMap<>();
        result.put("TYPE", "0");
        result.put("MOBILE", "18900000001");
        result.put("PERSON", "小");
        result.put("PERSONID", "350625199205131515");
        String token = SXZW_createToken(result);
//        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJQRVJTT05JRCI6IjYxMDQyMzE5ODkwNjA3MDkxOCIsIlBFUlNPTiI6IuW8oOW6tyIsIlRZUEUiOiIwIiwiTU9CSUxFIjoiMTUzOTkwNTk2MjMifQ.topdTaX2TSCKeRlPelrvCbCuXiTAsXBtl0Gn7wSLYX4";
        System.out.println(token);
        System.out.println(SXZW_verifyToken(token));

//        System.out.println(SXZW_verifyToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJCTFJNT0JJTEUiOiIiLCJMRUdBTFBFUlNPTklEIjoiIiwiUEVSU09OIjoi5p2O5ZubIiwiUEVSU09OX0lEIjoiNjE0MjMxOTg5IiwiTEVHQUxQRVJTT05QSE9ORSI6IiIsIkxFR0FMUEVSU09OIjoiIiwiVFlQRSI6IjEiLCJNT0JJTEUiOiIxNTM5OTA1OTYyMyJ9.h2tkCNUW6TWfErLHsgxoJmsvjN9i0lIE0D_NmxMo7i8"));

//        Map<String, String> result = new HashMap<>();
//        result.put("idNo", "003879");
//        result.put("name", "田午阳");
//        result.put("ukeySn", "");
//        result.put("organCode", "0");
//        result.put("organName", "田午阳");
//        result.put("orglevel", "1");
//        String token = BJZZ_createToken(result);
//        System.out.println(token);
//        System.out.println(BJZZ_verifyToken(token));
    }*/

}
