package com.roma.romaapi.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/***
 * Author: YL.Lou
 * Class: JWTUtil
 * Project: washes_base_backstage
 * Introduce: JWT的验证工具类 被生成Token的方法Service调用 也会被 拦截器调用 验签
 * DateTime: 2022-06-29 19:23
 ***/

@Slf4j
@Component
public class JWTUtil {
    // 为Redis存储准备的Key前缀 后边跟的是用户的 ID  例如：JWT_SIGN_1 查询到的是 MD5 之后的 用户密码 信息
    public static final String SIGN = "JWT_SIGN_";

    // 加盐
    private static final String SECRET = "rd!rew231sods4df?m2wsa";

    // redis用户token缓存时间,单位秒
    public static final long REDIS_USER_EXPIRE_TIME = 1800;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    /**
     * 获取token
     * @return token
     */
    public String getToken(Map userMapInfo) {

        Calendar instance = Calendar.getInstance();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // 默认令牌过期时间7天
        instance.add(Calendar.DATE, 7);

        JWTCreator.Builder builder = JWT.create();
        Object objectUserId = userMapInfo.get("id");
        String userId = objectUserId.toString();
        builder.withClaim("userId", userId)
                .withClaim("userLoginTime", String.valueOf(userMapInfo.get("loginTime")))
                .withClaim("userName", String.valueOf(userMapInfo.get("name")))
                .withClaim("expTime", simpleDateFormat.format(new Date(instance.getTime().getTime())));
        String jwtToken = builder.withExpiresAt(instance.getTime())
                .sign(Algorithm.HMAC256(userId));
        // 将缓存的信息添加到redis中
        String redisTokenKey = SIGN + jwtToken;
        stringRedisTemplate.opsForValue().set(redisTokenKey, userId, 60*30, TimeUnit.SECONDS);

        return jwtToken;
    }

    /**
     * 验证token合法性 成功返回token
     */
    public DecodedJWT verify(String token) throws Exception {
        // 从Redis中获取缓存中的token,判断是否过期
        String userId = stringRedisTemplate.opsForValue().get(SIGN + token);
        JWTVerifier build = JWT.require(Algorithm.HMAC256(userId)).build();

        return build.verify(token);
    }
}
