package com.muyu.common.core.utils;

import com.muyu.common.core.constant.SecurityConstants;
import com.muyu.common.core.constant.TokenConstants;
import com.muyu.common.core.text.Convert;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SecureDigestAlgorithm;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;

/**
 * Jwt工具类
 *
 * @author muyu
 */
public class JwtUtils {

    /**
     * 加密算法
     */
    private final static SecureDigestAlgorithm<SecretKey, SecretKey> ALGORITHM = Jwts.SIG.HS256;
    /**
     * 私钥 / 生成签名的时候使用的秘钥secret，一般可以从本地配置文件中读取，切记这个秘钥不能外露，只在服务端使用，在任何场景都不应该流露出去。
     * 一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
     * 应该大于等于 256位(长度32及以上的字符串)，并且是随机的字符串
     */
    private final static String secret = TokenConstants.SECRET;
    /**
     * 秘钥实例
     */
    public static final SecretKey KEY = Keys.hmacShaKeyFor(secret.getBytes());
    /**
     * jwt签发者
     */
    private final static String JWT_ISS = "MUYU";
    /**
     * jwt主题
     */
    private final static String SUBJECT = "Peripherals";


    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     *
     * @return 令牌
     */
    public static String createToken (Map<String, Object> claims) {
        return Jwts.builder()
                // 设置头部信息header
                .header().add("typ", "JWT").add("alg", "HS256").and()
                // 设置自定义负载信息payload
                .claims(claims)
                // 签发时间
                .issuedAt(new Date())
                // 主题
                .subject(SUBJECT)
                // 签发者
                .issuer(JWT_ISS)
                // 签名
                .signWith(KEY, ALGORITHM)
                .compact();
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     *
     * @return 数据声明
     */
    public static Claims parseToken (String token) {
        return Jwts.parser()
                .verifyWith(KEY)
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }

    /**
     * 根据令牌获取用户标识
     *
     * @param token 令牌
     *
     * @return 用户ID
     */
    public static String getUserKey (String token) {
        Claims claims = parseToken(token);
        return getValue(claims, SecurityConstants.USER_KEY);
    }

    /**
     * 根据令牌获取用户标识
     *
     * @param claims 身份信息
     *
     * @return 用户ID
     */
    public static String getUserKey (Claims claims) {
        return getValue(claims, SecurityConstants.USER_KEY);
    }

    /**
     * 根据令牌获取用户ID
     *
     * @param token 令牌
     *
     * @return 用户ID
     */
    public static String getUserId (String token) {
        Claims claims = parseToken(token);
        return getValue(claims, SecurityConstants.DETAILS_USER_ID);
    }

    /**
     * 根据身份信息获取用户ID
     *
     * @param claims 身份信息
     *
     * @return 用户ID
     */
    public static String getUserId (Claims claims) {
        return getValue(claims, SecurityConstants.DETAILS_USER_ID);
    }

    /**
     * 根据令牌获取用户名
     *
     * @param token 令牌
     *
     * @return 用户名
     */
    public static String getUserName (String token) {
        Claims claims = parseToken(token);
        return getValue(claims, SecurityConstants.DETAILS_USERNAME);
    }

    /**
     * 根据身份信息获取用户名
     *
     * @param claims 身份信息
     *
     * @return 用户名
     */
    public static String getUserName (Claims claims) {
        return getValue(claims, SecurityConstants.DETAILS_USERNAME);
    }

    /**
     * 根据身份信息获取SAAS标识
     *
     * @param claims 身份信息
     * @return SAAS标识
     */
    public static String getSaaSKey(Claims claims) {
        return getValue(claims, SecurityConstants.SAAS_KEY);
    }

    /**
     * 根据身份信息获取键值
     *
     * @param claims 身份信息
     * @param key    键
     *
     * @return 值
     */
    public static String getValue (Claims claims, String key) {
        return Convert.toStr(claims.get(key), "");
    }

    /**
     *
     * @param claims 身份信息
     * @return 值
     */
    public static String getDeptId(Claims claims) {
        return getValue(claims, SecurityConstants.DETAILS_DEPT_ID);
    }
}
