package com.jiayue.ssi.util;

import com.jiayue.ssi.entity.SysUser;
import io.jsonwebtoken.*;
import lombok.Data;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
* 生成令牌，验证等等一些操作
* @author xsl
* @date 2023/2/16
*/
@Data
@Component
public class JwtTokenUtil {

    private String secret = "jiayue";

    private String authorization;

    /**
     * 从数据声明生成令牌
     *
     * @param claims 数据声明
     * @return 令牌
     */
    private String generateToken(Map<String, Object> claims) {
        // 过期时长60分钟
        Long expiration = 60*1000*60L;
        Date expirationDate = new Date(System.currentTimeMillis() + expiration);
        return Jwts.builder().setClaims(claims).setExpiration(expirationDate).setIssuedAt(new Date(System.currentTimeMillis())).signWith(SignatureAlgorithm.HS512, secret).compact();
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    public Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        }
        catch (ExpiredJwtException e) {
            // token过期
            throw e;
        }
        catch (Exception e) {
            // 无效token
            claims = null;
        }
        return claims;
    }

    /**
     * 生成令牌
     *
     * @param userDetails 用户
     * @return 令牌
     */
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<String, Object>(16);
        claims.put(Claims.SUBJECT, userDetails.getUsername());
        claims.put(Claims.ISSUED_AT, new Date());
        return generateToken(claims);
    }

    /**
     * 从令牌中获取用户名
     *
     * @param token 令牌
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 判断令牌是否过期
     *
     * @param token 令牌
     * @return 是否过期
     */
    public Boolean isTokenExpired(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 刷新令牌
     *
     * @param token 原令牌
     * @return 新令牌
     */
    public String refreshToken(String token) {
        String refreshedToken;
        try {
            Claims claims = getClaimsFromToken(token);
            claims.put(Claims.ISSUED_AT, new Date());
            refreshedToken = generateToken(claims);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    /**
     * 验证令牌
     *
     * @param token       令牌
     * @param userDetails 用户
     * @return 是否有效
     */
    public Boolean validateToken(String token, UserDetails userDetails) {
        SysUser user = (SysUser) userDetails;
        String username = getUsernameFromToken(token);
        return (username.equals(user.getUsername()) && !isTokenExpired(token));
    }

    /**
     * 解析token内容
     * @param token
     */
    public void analysisToken(String token){
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
        JwsHeader header = claimsJws.getHeader();
        Claims body = claimsJws.getBody();

        System.out.println("jwt header:" + header);
        System.out.println("jwt body:" + body);
        System.out.println("jwt body user-id:" + body.get("user_id", String.class));
    }

    public static void main(String[] args)throws Exception {
        JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
//        Map<String, Object> claims = new HashMap<String, Object>(16);
//        claims.put(Claims.SUBJECT, "Test");
////        claims.put(Claims.ISSUED_AT, new Date(System.currentTimeMillis()));
//        String token=jwtTokenUtil.generateToken(claims);
//        System.out.println(jwtTokenUtil.getUsernameFromToken(token));
//        System.out.println(jwtTokenUtil.isTokenExpired(token));
//        Claims claims1 = jwtTokenUtil.getClaimsFromToken(token);
////        System.out.println("过期时间："+claims1.getExpiration());
////        System.out.println("过期时间提前2分钟："+new Date(claims1.getExpiration().getTime()-1000*60*2));
////        Thread.sleep(3000L);
//        System.out.println(token);
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        System.out.println("签发时间："+ sdf.format(claims1.getIssuedAt()));

        try {
            Claims claims = jwtTokenUtil.getClaimsFromToken("eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJUZXN0IiwiZXhwIjoxNjc5MzA0MTUyLCJpYXQiOjE2NzkzMDIzNTJ9.Mtv8qJHbjLdnf52VRodqYqp1B2RI1iB_SxzIO92QccwmshQasJOqQL_rhRhgHFcwZRkUmfdwPy06UsWEr3aa7w");
            if (claims==null){
                System.out.println("无效");
            }
        }
        catch (ExpiredJwtException expiredJwtException){
            System.out.println("过期："+expiredJwtException.getClaims().getSubject());
        }
//        System.out.println(jwtTokenUtil.getUsernameFromToken("eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJUZXN0IiwiZXhwIjoxNjc5MzA0MTUyLCJpYXQiOjE2NzkzMDIzNTJ9.Mtv8qJHbjLdnf52VRodqYqp1B2RI1iB_SxzIO92QccwmshQasJOqQL_rhRhgHFcwZRkUmfdwPy06UsWEr3zZab"));
// eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJUZXN0IiwiZXhwIjoxNjc5MzA0MTUyLCJpYXQiOjE2NzkzMDIzNTJ9.Mtv8qJHbjLdnf52VRodqYqp1B2RI1iB_SxzIO92QccwmshQasJOqQL_rhRhgHFcwZRkUmfdwPy06UsWEr3zZ7w
// eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJUZXN0IiwiZXhwIjoxNjc5MzA0MTY5LCJpYXQiOjE2NzkzMDIzNjl9.x0CiNFezdegvRzmFSQyCzzmNrA-N5g4QaHMZOQubThx6LIOFM8jkoPJgEWc8xUlUipTW5CqFKfxn0z0O0xVvoQ
    }
}
