package com.xindazhou.gateway.core.jwt;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Base64;
import java.util.List;

/**
 * Gateway JWT 工具类（简化版，只包含验证功能）
 * 用于 Gateway 验证 JWT Token
 *
 * @author xindazhou
 */
@Slf4j
public class GatewayJwtUtil {

    private static RSAPublicKey publicKey;
    private static Algorithm algorithm;
    private static JWTVerifier verifier;
    private static String issuer = "xindazhou-oauth2";

    /**
     * 初始化公钥（用于验证 Token）
     *
     * @param publicKeyPath 公钥路径
     * @param resourceLoader Spring ResourceLoader
     */
    public static void init(String publicKeyPath, ResourceLoader resourceLoader) {
        try {
            // 加载公钥（用于验证 Token）
            if (StrUtil.isNotEmpty(publicKeyPath)) {
                String publicKeyContent = readKeyFile(publicKeyPath, resourceLoader);
                publicKey = getPublicKey(publicKeyContent);
                // Gateway 只需要验证，使用公钥即可
                algorithm = Algorithm.RSA256(publicKey, null);
                verifier = JWT.require(algorithm).withIssuer(issuer).build();
                log.info("Gateway JWT 公钥初始化成功: {}", publicKeyPath);
            } else {
                log.warn("Gateway JWT 公钥路径为空，无法验证 Token");
            }
        } catch (Exception e) {
            log.error("Gateway JWT 初始化失败: publicKeyPath={}", publicKeyPath, e);
            throw new RuntimeException("Gateway JWT 初始化失败", e);
        }
    }

    /**
     * 验证 JWT Token
     *
     * @param token JWT Token
     * @return 解码后的 JWT，验证失败返回 null
     */
    public static DecodedJWT verifyToken(String token) {
        if (StrUtil.isEmpty(token)) {
            log.warn("Gateway JWT Token 验证失败: Token 为空");
            return null;
        }
        if (verifier == null) {
            log.warn("Gateway JWT 验证器未初始化");
            return null;
        }
        try {
            return verifier.verify(token);
        } catch (JWTVerificationException e) {
            log.warn("Gateway JWT Token 验证失败: {}, tokenPrefix={}",
                    e.getMessage(),
                    token.length() > 20 ? token.substring(0, 20) + "..." : token);
            return null;
        } catch (Exception e) {
            log.error("Gateway JWT Token 验证异常: {}", e.getMessage(), e);
            return null;
        }
    }

    /**
     * 从 JWT 中获取用户ID
     */
    public static Long getUserId(DecodedJWT jwt) {
        if (jwt == null) {
            return null;
        }
        try {
            return jwt.getClaim("uid").asLong();
        } catch (Exception e) {
            log.warn("从 JWT 中获取用户ID 失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从 JWT 中获取用户类型
     */
    public static Integer getUserType(DecodedJWT jwt) {
        if (jwt == null) {
            return null;
        }
        try {
            return jwt.getClaim("userType").asInt();
        } catch (Exception e) {
            log.warn("从 JWT 中获取用户类型失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从 JWT 中获取租户ID
     */
    public static Long getTenantId(DecodedJWT jwt) {
        if (jwt == null) {
            return null;
        }
        try {
            return jwt.getClaim("tenantId").asLong();
        } catch (Exception e) {
            log.warn("从 JWT 中获取租户ID失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从 JWT 中获取权限范围
     */
    public static List<String> getScopes(DecodedJWT jwt) {
        if (jwt == null) {
            return null;
        }
        try {
            String scopesStr = jwt.getClaim("scopes").asString();
            if (StrUtil.isEmpty(scopesStr)) {
                return null;
            }
            return List.of(scopesStr.split(","));
        } catch (Exception e) {
            log.warn("从 JWT 中获取权限范围失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从 JWT 中获取过期时间
     */
    public static LocalDateTime getExpiresTime(DecodedJWT jwt) {
        if (jwt == null || jwt.getExpiresAt() == null) {
            return null;
        }
        return LocalDateTime.ofInstant(jwt.getExpiresAt().toInstant(), ZoneId.systemDefault());
    }

    /**
     * 读取密钥文件内容
     */
    private static String readKeyFile(String keyPath, ResourceLoader resourceLoader) throws IOException {
        Resource resource = resourceLoader.getResource(keyPath);
        if (!resource.exists()) {
            throw new IOException("密钥文件不存在: " + keyPath);
        }
        try (var inputStream = resource.getInputStream()) {
            return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
        }
    }

    /**
     * 从 PEM 格式的字符串中提取公钥
     */
    private static RSAPublicKey getPublicKey(String publicKeyContent) {
        try {
            // 移除 PEM 格式的头部和尾部
            String publicKeyPEM = publicKeyContent
                    .replace("-----BEGIN PUBLIC KEY-----", "")
                    .replace("-----END PUBLIC KEY-----", "")
                    .replaceAll("\\s", "");

            // Base64 解码
            byte[] keyBytes = Base64.getDecoder().decode(publicKeyPEM);

            // 创建公钥规范
            X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return (RSAPublicKey) keyFactory.generatePublic(spec);
        } catch (Exception e) {
            log.error("解析公钥失败", e);
            throw new RuntimeException("解析公钥失败", e);
        }
    }
}

