package org.example.Utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.jsonwebtoken.*;
import org.example.Entity.System.LoginUserInfo;
import org.springframework.stereotype.Component;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtHelp {
    private static final Logger log = LoggerFactory.getLogger(JwtHelp.class);


    private static final String KEY_CONTAINER_NAME = "LKSJJWT_6789_ZYW_RSA";
    private static final String SECRET = resolveJwtSecret();
    private static final int RSA_KEY_SIZE = 2048;

    private static volatile KeyPair rsaKeyPair = null;

    private static String resolveJwtSecret() {
        String secret = System.getenv("JWT_SECRET");
        if (secret == null || secret.trim().isEmpty()) {
            secret = System.getProperty("jwt.secret");
        }
        return secret;
    }

    private static KeyPair getRsaKeyPair() {
        KeyPair keyPair = rsaKeyPair;
        if (keyPair != null) {
            return keyPair;
        }

        synchronized (JwtHelp.class) {
            if (rsaKeyPair == null) {
                rsaKeyPair = generateRsaKeyPair();
            }
            return rsaKeyPair;
        }
    }

    private static KeyPair generateRsaKeyPair() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(RSA_KEY_SIZE);
            return keyPairGenerator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("Initialize RSA key pair failed", e);
        }
    }

    public JwtHelp() {
        try {
            // 生成RSA密钥对（替代C#的RSACryptoServiceProvider）
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(RSA_KEY_SIZE);
            rsaKeyPair = keyPairGenerator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("初始化RSA密钥对失败", e);
        }
    }

    /**
     * 设置用户缓存（默认7200秒过期）
     */
    public void setUserCache(LoginUserInfo user) {
        setUserCache(user, 7200);
    }

    /**
     * 设置用户缓存
     *
     * @param user 用户信息
     * @param exp  过期时间（秒）
     */
    public static void setUserCache(LoginUserInfo user, int exp) {
        String cacheKey = String.format("usertoken_%s_%s_%d_%s",
                user.UserName,
                user.UserId,
                user.ServerId,
                user.LoginOs);
        CacheUtil.set(cacheKey, user, Duration.ofSeconds(exp), null);
    }

    /**
     * 从缓存获取用户信息
     */
    private static Object getUserFromCache(LoginUserInfo user) {
        if (user == null) {
            return null;
        }
        String cacheKey = String.format("usertoken_%s_%s_%d_%s",
                user.UserName,
                user.UserId,
                user.ServerId,
                user.LoginOs);
        return CacheUtil.get(cacheKey);
    }

    /**
     * 移除用户缓存
     */
    public static void removeUserCache(LoginUserInfo user) {
        if (user == null) {
            return;
        }
        String cacheKey = String.format("usertoken_%s_%s_%d_%s",
                user.UserName,
                user.UserId,
                user.ServerId,
                user.LoginOs);
        CacheUtil.remove(cacheKey);
    }

    /**
     * 从缓存获取Token信息
     */
    private static Object getDictFromCache(String token) {
        return CacheUtil.getCacheItem(token, (key) -> {
            try {
                // 解析JWT令牌
                Claims claims = Jwts.parserBuilder()
                        .setSigningKey(getRsaKeyPair().getPublic())
                        .build()
                        .parseClaimsJws(token)
                        .getBody();
                return convertClaimsToMap(claims);
            } catch (Exception e) {
                return new HashMap<String, Object>();
            }
        }, Duration.ofSeconds(7200), null, true); // 2小时过期（7200秒）
    }

    /**
     * 生成JWT令牌
     *
     * @param user 用户信息
     * @param exp  过期时间（秒）
     * @return 令牌字符串
     */
    public static String createToken(LoginUserInfo user, int exp) {
        if (user == null) {
            return null;
        }

        try {
            // 计算过期时间
            Instant now = Instant.now();
            Instant expiration = now.plusSeconds(exp);

            // 构建载荷
            Map<String, Object> payload = new HashMap<>();
            payload.put("exp", expiration.getEpochSecond());
            payload.put("UserId", user.UserId);
            payload.put("UserCode", user.UserCode);
            payload.put("UserName", user.UserName);
            payload.put("LoginOs", user.LoginOs);
            payload.put("ServerId", user.ServerId);

            // 生成令牌
            String token = Jwts.builder()
                    .setClaims(payload)
                    .signWith(getRsaKeyPair().getPrivate(), SignatureAlgorithm.RS256)
                    .compact();

            // 缓存令牌
            CacheUtil.set(token, payload, Duration.ofSeconds(7200), null); // 2小时过期
            user.Token = (token);
            setUserCache(user, exp);

            return token;
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 生成JWT令牌（默认3600秒过期）
     */
    public String createToken(LoginUserInfo user) {
        return createToken(user, 3600);
    }

    /**
     * 验证令牌并转换为指定类型
     */
    public static <T> T validToken(String token, Class<T> clazz) {
        try {
            @SuppressWarnings("unchecked")
            Map<String, Object> userInfo = (Map<String, Object>) getDictFromCache(token);

            if (!validDate(userInfo)) {
                return null;
            }

            if (userInfo != null) {
                if (clazz == Map.class) {
                    return clazz.cast(userInfo);
                } else if (clazz == LoginUserInfo.class) {
                    LoginUserInfo user = new LoginUserInfo();
                    user.UserId = (userInfo.get("UserId").toString());
                    user.UserCode = (userInfo.get("UserCode").toString());
                    user.UserName = (userInfo.get("UserName").toString());
                    user.LoginOs = (userInfo.get("LoginOs").toString());
                    user.ServerId = (Integer.parseInt(userInfo.get("ServerId").toString()));
                    user.FromToken = (true);

                    // 从缓存获取用户信息
                    Object cacheUser = getUserFromCache(user);
                    if (cacheUser != null && cacheUser instanceof LoginUserInfo) {
                        user = (LoginUserInfo) cacheUser;
                    }

                    user.Token = (token);
                    return clazz.cast(user);
                }
            }
            return null;
        } catch (ExpiredJwtException e) {
            log.debug(String.valueOf("Token已过期"));
        } catch (JwtException e) {
            log.debug(String.valueOf("Token签名无效"));
        } catch (Exception e) {
            return null;
        }
        return null;
    }

    /**
     * 验证令牌过期时间
     */
    public static boolean validDate(Map<String, Object> userInfo) {
        if (userInfo == null || !userInfo.containsKey("exp")) {
            return false;
        }

        long expSeconds = Long.parseLong(userInfo.get("exp").toString());
        Instant expInstant = Instant.ofEpochSecond(expSeconds);
        return expInstant.isAfter(Instant.now());
    }

    /**
     * 刷新令牌
     */
    public static String refreshToken(LoginUserInfo user, String token, int exp) {
        @SuppressWarnings("unchecked")
        Map<String, Object> userInfo = (Map<String, Object>) getDictFromCache(token);

        if (userInfo != null && userInfo.containsKey("exp")) {
            long expSeconds = Long.parseLong(userInfo.get("exp").toString());
            Instant expInstant = Instant.ofEpochSecond(expSeconds);
            Instant now = Instant.now();

            // 检查是否需要刷新（已过期或即将在10分钟内过期）
            if (expInstant.isBefore(now) ||
                    expInstant.isAfter(now) &&
                            expInstant.minusSeconds(600).isBefore(now)) {

                LoginUserInfo tokenUser = new LoginUserInfo();
                tokenUser.UserId = (userInfo.get("UserId").toString());
                tokenUser.UserCode = (userInfo.get("UserCode").toString());
                tokenUser.UserName = (userInfo.get("UserName").toString());
                tokenUser.LoginOs = (userInfo.get("LoginOs").toString());

                Object cacheUser = getUserFromCache(tokenUser);
                LoginUserInfo actualUser = (cacheUser instanceof LoginUserInfo) ? (LoginUserInfo) cacheUser : user;

                if (actualUser != null) {
                    CacheUtil.remove(token);
                    return createToken(actualUser, exp);
                }
            }
        } else if (user != null) {
            CacheUtil.remove(token);
            return createToken(user, exp);
        }

        return null;
    }

    /**
     * 刷新令牌（默认3600秒过期）
     */
    public String refreshToken(LoginUserInfo user, String token) {
        return refreshToken(user, token, 3600);
    }

    /**
     * 将Claims转换为Map
     */
    private static Map<String, Object> convertClaimsToMap(Claims claims) {
        Map<String, Object> map = new HashMap<>();
        for (Map.Entry<String, Object> entry : claims.entrySet()) {
            map.put(entry.getKey(), entry.getValue());
        }
        return map;
    }
}
