package com.example.sjkbf.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * JWT 工具类
 * - 负责 Token 的生成、解析、验证
 * - 采用 HMAC-SHA 算法进行签名，保证安全性
 * - 适配 JJWT 0.11.x 版本
 */
@Component
public class JwtTokenUtil {

    // 从配置文件中注入 JWT 密钥和过期时间
    @Value("${jwt.secret}")
    private String secret;      // 密钥（至少 32 位，推荐 64 位随机字符串）

    @Value("${jwt.expiration}")
    private Long expiration;    // Token 有效期（秒）

    /**
     * 生成安全的 HMAC-SHA 密钥
     * - 避免直接使用原始字符串，提升安全性
     */
    private SecretKey generateSecretKey() {
        return Keys.hmacShaKeyFor(secret.getBytes());
    }

    /**
     * 生成 Token
     * @param userDetails 用户信息（包含用户名、权限等）
     * @return Token 字符串
     */
    public String generateToken(UserDetails userDetails) {
        // 1. 定义 Token 的 Claims（载荷）
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", userDetails.getUsername());
        // 将权限列表转换为字符串（例如 "ROLE_ADMIN,ROLE_USER"）
        claims.put("authorities", userDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList()));

        // 2. 生成 Token
        return Jwts.builder()
                .setClaims(claims)                      // 自定义载荷
                .setSubject(userDetails.getUsername())  // 主题（通常放用户名）
                .setIssuedAt(new Date())                // 签发时间
                .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000)) // 过期时间
                .signWith(generateSecretKey())          // 签名算法和密钥
                .compact();                             // 生成字符串
    }

    /**
     * 从 Token 中解析用户名
     * @param token JWT Token
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        return parseToken(token).getSubject();
    }

    /**
     * 从 Token 中解析权限列表
     * @param token JWT Token
     * @return 权限列表（例如 ["ROLE_ADMIN", "ROLE_USER"]）
     */
    public List<String> getAuthoritiesFromToken(String token) {
        Claims claims = parseToken(token);
        return claims.get("authorities", List.class);
    }

    /**
     * 验证 Token 是否有效（基础验证）
     * - 检查签名是否正确
     * - 检查是否过期
     * @param token JWT Token
     * @return 是否有效
     */
    public boolean validateToken(String token) {

            Claims claims = parseToken(token);
            // 检查是否过期（parseToken 内部已自动验证过期时间）
            return !claims.getExpiration().before(new Date());

    }

    /**
     * 验证 Token 是否属于指定用户（业务层扩展验证）
     * @param token       JWT Token
     * @param userDetails 用户信息
     * @return 是否匹配
     */
    public boolean validateTokenBelongsToUser(String token, UserDetails userDetails) {
        String username = getUsernameFromToken(token);
        return username.equals(userDetails.getUsername());
    }

    /**
     * 解析 Token（内部方法）
     * @param token JWT Token
     * @return 解析后的 Claims 对象
     * @throws JwtException 解析失败时抛出异常（如签名错误、格式错误）
     */
    public Claims parseToken(String token) {
        try {
            return Jwts.parserBuilder()
                    .setSigningKey(generateSecretKey())
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (JwtException e) {
            throw new JwtException("Token 已过期");
        }
    }
    // ---------- 扩展方法：自定义 Claims ----------

    /**
     * 添加自定义 Claim（在生成 Token 前调用）
     * 示例：添加用户ID
     * Map<String, Object> claims = new HashMap<>();
     * claims.put("userId", 123);
     * String token = jwtTokenUtil.generateToken(userDetails, claims);
     */
    public String generateToken(UserDetails userDetails, Map<String, Object> customClaims) {
        Map<String, Object> claims = new HashMap<>();
        claims.putAll(customClaims); // 合并自定义 Claims
        claims.put("authorities", userDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toList()));

        return Jwts.builder()
                .setClaims(claims)
                .setSubject(userDetails.getUsername())
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
                .signWith(generateSecretKey())
                .compact();
    }

    /**
     * 获取自定义 Claim
     * 示例：Long userId = jwtTokenUtil.getClaimFromToken(token, "userId", Long.class);
     */
    public <T> T getClaimFromToken(String token, String claimName, Class<T> clazz) {
        Claims claims = parseToken(token);
        return claims.get(claimName, clazz);
    }


    /**
     * 从请求中获取 Token
     * @param request
     * @return
     */
    public String getTokenFromRequest(HttpServletRequest request) {
        String header = request.getHeader("Authorization");
        if (header != null && header.startsWith("Bearer ")) {
            return header.substring(7);
        }
        return null;
    }
}