package com.bcxin.Infrastructures.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.bcxin.Infrastructures.exceptions.BadTenantException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * @author Administrator
 * @create 2024-09-05 15:29
 */
@Component
public class BjNwJwtUtil {

    private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class);
    /**
     * token在redis中key的前缀
     */
    public static final String PSC_TOKEN_PREFIX = "psc_token_";
    /**
     * 摘要 盐
     */
    private static final String SIGNATURE_KEY = "!@#zhian123O0zhang";

    /**
     * HMAC 摘要算法
     */
    private static final Algorithm SIGNATURE_ALGORITHM;

    static {
        try {
            SIGNATURE_ALGORITHM = Algorithm.HMAC256(SIGNATURE_KEY);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * token最长有效期
     */
    private static final long SURVIVAL_TIME = 24 * 60 * 60 * 1000;

    /**
     * 不操作的情况下token有效期
     */
    private static final long NO_OPERATION_TIME = 60 * 60;

    public String createToken(Map<String, String> verifyInfoMap) {
        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() + SURVIVAL_TIME))
                //.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;
    }


    public Map<String, String> verifyToken(String token) throws JWTVerificationException, BadTenantException {
        DecodedJWT jwt = null;
        try {
            token = new String(Base64Utils.decodeFromString(token), StandardCharsets.UTF_8);
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SIGNATURE_KEY)).build();
            jwt = verifier.verify(token);
            /*if (jwt.getExpiresAt().before(new Date())) {
                logger.error("token已过期");
                return null;
            }*/
            String idNo = jwt.getClaim("idNo").asString();
            if (StringUtils.isEmpty(idNo)) {
                logger.error("token携带参数不完整");
                throw new BadTenantException("token携带参数不完整");
            }
        } catch (Exception e) {
            if(StringUtils.isNotEmpty(e.getMessage())&& e.getMessage().contains("The Token has expired on Sat")){
                throw new BadTenantException("token解码异常：token已过期");
            }else{
                logger.error(e.getMessage());
                throw new BadTenantException("token解码异常："+e.getMessage());
            }
        }
        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());
        result.put("roleCode", jwt.getClaim("roleCode").asString());
        result.put("thirdLevelOrgCode", jwt.getClaim("thirdLevelOrgCode").asString());
        result.put("secondLevelOrgCode", jwt.getClaim("secondLevelOrgCode").asString());
        return result;
    }

}
