package com.simuwang.shiro.core.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.simuwang.base.config.DaqProperties;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;

@Component
public class JwtContext {
    public static final String HEADER = "Authorization";
    //    private static final String SECRET = "qwertyuiopasdfghjklzxcvbnm1234567890qwertyuiopasdfghjklzxcvbnm12";
//    private static final long EXPIRE = 60 * 24 * 7;
    private static final Cache<String, String> USER_TOKEN_CACHE = Caffeine.newBuilder().maximumSize(16384L).build();
    private final DaqProperties properties;
    public JwtContext(DaqProperties properties) {
        this.properties = properties;
    }

//    public static void main(String[] args) {
//        JwtContext jwtUtil = new JwtContext();
//        String token = jwtUtil.generateToken("admin");
//        System.out.println("token = " + token);
//
//        Claims claims = jwtUtil.getClaimsByToken(token);
//        System.out.println("claims = " + claims);
//
//        String username = jwtUtil.getClaimFiled(token, "username");
//        System.out.println("username = " + username);
//    }

    public void setUserCache(String token) {
        String username = this.getClaimsByToken(token).getSubject();
        USER_TOKEN_CACHE.put(username, token);
    }

    public String getUserCache(String username) {
        return USER_TOKEN_CACHE.getIfPresent(username);
    }

    public void cleanUserCache(String username) {
        USER_TOKEN_CACHE.invalidate(username);
    }

    /**
     * 生成jwt token
     */
    public String generateToken(String username) {
        SecretKey signingKey = Keys.hmacShaKeyFor(this.properties.getTokenSecret().getBytes(StandardCharsets.UTF_8));
        //过期时间
        LocalDateTime tokenExpirationTime = LocalDateTime.now().plusMinutes(this.properties.getTokenExpire());
        return Jwts.builder()
                .signWith(signingKey, Jwts.SIG.HS512)
                .header().add("typ", "JWT").and()
                .issuedAt(Timestamp.valueOf(LocalDateTime.now()))
                .subject(username)
                .expiration(Timestamp.valueOf(tokenExpirationTime))
                .claims(Map.of("username", username))
                .compact();
    }

    public Claims getClaimsByToken(String token) {
        SecretKey signingKey = Keys.hmacShaKeyFor(this.properties.getTokenSecret().getBytes(StandardCharsets.UTF_8));
        return Jwts.parser()
                .verifyWith(signingKey)
                .build()
                .parseSignedClaims(token)
                .getPayload();
    }

    /**
     * 检查token是否过期
     *
     * @return true：过期
     */
    public boolean isTokenExpired(Date expiration) {
        return expiration.before(new Date());
    }

    /**
     * 获得token中的自定义信息,一般是获取token的username，无需secret解密也能获得
     *
     * @param token
     * @param filed
     * @return
     */
    public String getClaimFiled(String token, String filed) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(filed).asString();
        } catch (JWTDecodeException e) {
//            log.error("JwtContext getClaimFiled error: ", e);
            return null;
        }
    }
}
