package com.simuwang.shiro.core.jwt;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
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.Map;

@Component
public class JwtContext {
    public static final String HEADER = "Authorization";
    private static final Cache<String, Map<String, String>> USER_TOKEN_CACHE = Caffeine.newBuilder().maximumSize(16384L).build();
    private final DaqProperties properties;

    public JwtContext(DaqProperties properties) {
        this.properties = properties;
    }

    /**
     * 设置用户token缓存
     *
     * @param requestIP 请求的ip地址
     * @param token     用户登录token
     */
    private void setUserCache(String requestIP, String token) {
        String username = this.getClaimsByToken(token).getSubject();
        Map<String, String> tokenMap = USER_TOKEN_CACHE.getIfPresent(username);
        if (MapUtil.isEmpty(tokenMap)) {
            tokenMap = MapUtil.newConcurrentHashMap(16);
        }
        tokenMap.putIfAbsent(requestIP, token);
        USER_TOKEN_CACHE.put(username, tokenMap);
    }

    /**
     * 获取用户token缓存
     *
     * @param username  用户账号
     * @param requestIp 请求ip
     * @return /
     */
    public String getUserCache(String username, String requestIp) {
        Map<String, String> tokenMap = USER_TOKEN_CACHE.getIfPresent(username);
        if (MapUtil.isNotEmpty(tokenMap)) {
            return tokenMap.get(requestIp);
        }
        return null;
    }

    /**
     * 清理token缓存
     *
     * @param username  用户账号
     * @param requestIp 请求ip
     */
    public void cleanUserCache(String username, String requestIp) {
        Map<String, String> tokenMap = USER_TOKEN_CACHE.getIfPresent(username);
        if (MapUtil.isNotEmpty(tokenMap)) {
            tokenMap.remove(requestIp);
        }
    }

    /**
     * 生成jwt token
     */
    public synchronized String generateToken(String username, String requestIp) {
        String token = this.getUserCache(username, requestIp);
        if (StrUtil.isBlank(token)) {
            SecretKey signingKey = Keys.hmacShaKeyFor(this.properties.getTokenSecret().getBytes(StandardCharsets.UTF_8));
            //过期时间
            LocalDateTime tokenExpirationTime = LocalDateTime.now().plusMinutes(this.properties.getTokenExpire());
            token = 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();
            this.setUserCache(requestIp, token);
        }
        return token;
    }

    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();
    }
}
