package com.backendsys.modules.common.config.security.utils;

import cn.hutool.core.convert.Convert;
import cn.hutool.json.JSONUtil;
import com.backendsys.modules.common.config.security.entity.SecurityAppUserInfo;
import com.backendsys.modules.common.config.security.entity.SecurityUserInfo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import java.util.function.Function;

/**
 * TODO 完成JWT的验证服务
 * JWT工具类
 *
 * @author ss_419
 * @version 1.0
 * @date 2023/3/3 11:16
 */

@Service
public class JwtUtil {
    /**
     * 创建一个最终字符串，这个字符串称为密钥
     * https://allkeysgenerator.com/
     *
     * JWT最低要求的安全级别是256bit
     */
    // 3F4428472B4B6250655368566D5971337336763979244226452948404D635166
    private static final String SECRET_KEY = "452948404D635166546A576E5A7134743777217A25432A462D4A614E64526755";

    /**
     * 令牌有效期毫秒 (86400000 = 1天 = 24小时)
     */
    // private static final long TOKEN_EXPIRED = 86400000;


    /**
     * 创建 Token (系统用户)
     * @param securityUserInfo
     * @return
     */
    public String createSystemJwtToken(SecurityUserInfo securityUserInfo) {
        return Jwts.builder()
            // subject 代表这个JWT的主体，即它的所有人
            .subject(securityUserInfo.getLast_login_uuid())
            .claim("userInfo", securityUserInfo)
            .claim("target", "System")
            .signWith(getSignInKey())
            .expiration(Convert.toDate(securityUserInfo.getToken_expiration()))
            .compact();
    }

    /**
     * 创建 Token (APP用户)
     * @param securityAppUserInfo
     * @return
     */
    public String createAppJwtToken(SecurityAppUserInfo securityAppUserInfo) {
        return Jwts.builder()
            // subject 代表这个JWT的主体，即它的所有人
            .subject(securityAppUserInfo.getLast_login_uuid())
            .claim("userInfo", securityAppUserInfo)
            .signWith(getSignInKey())
            .expiration(Convert.toDate(securityAppUserInfo.getToken_expiration()))
            .compact();
    }


//    /**
//     * 创建Token (即将弃用)
//     */
//    public String createSystemToken(Map<String, Object> sysUser) {
//
//        System.out.println("createSystemToken:");
//        System.out.println(sysUser);
//
//        Date expiration = (Date) sysUser.get("token_expiration");   // 过期时间由 isRemember 决定
//        return Jwts.builder()
//            // subject 代表这个JWT的主体，即它的所有人
//            .subject(String.valueOf(sysUser.get("last_login_uuid")))
//            .claim("user_id", sysUser.get("id"))
//            .claim("username", sysUser.get("username"))
//            .claim("is_super", sysUser.get("is_super"))
//            .claim("modules", sysUser.get("modules"))
//            .claim("target", "System")
//
//            .claim("UserInfo", JSONUtil.toJsonStr(sysUser))
//
//            .signWith(getSignInKey())
//            .expiration(expiration)
//            .compact();
//    }



    /**
     * 创建Token (sysMember 会员用户 实体类)
     */
    public String createMemberToken(Map<String, Object> sysMember) {
        Date expiration = (Date) sysMember.get("token_expiration");
        return Jwts.builder()
//                .setSubject(String.valueOf(sysMember.get("id")))
//                .setSubject(String.valueOf(sysMember.get("last_login_uuid")))
                .subject(String.valueOf(sysMember.get("last_login_uuid")))
                .claim("member_id", sysMember.get("id"))
                .claim("open_id", sysMember.get("open_id"))
                .claim("target", "Member")
//                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .signWith(getSignInKey())
                .expiration(expiration)
                .compact();
    }

    /**
     * 1、解析token字符串中的加密信息【加密算法&加密密钥】, 提取所有声明的方法
     * @param token
     * @return
     */
    public Claims extractAllClaims(String token){
        try {
            return Jwts.parser().verifyWith(getSignInKey()).build().parseSignedClaims(token).getPayload();
        } catch (JwtException e) {
            System.out.println("Token 解析失败: " + e.getMessage());
        }
        return null;
    }

    /**
     * 2、获取签名密钥的方法
     * @return 基于指定的密钥字节数组创建用于HMAC-SHA算法的新SecretKey实例
     */
//    private Key getSignInKey() {
//        byte[] keyBytes = Decoders.BASE64.decode(SECRET_KEY);
//        return Keys.hmacShaKeyFor(keyBytes);
//    }
    private SecretKey getSignInKey() {
        byte[] bytes = Base64.getDecoder().decode(SECRET_KEY.getBytes(StandardCharsets.UTF_8));
        return new SecretKeySpec(bytes, "HmacSHA256");
    }

    /**
     * 3、解析token字符串中的权限信息
     * @param token
     * @return
     */
    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    /**
     * 4、从token中解析出username
     * @param token
     * @return
     */
    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    /**
     * 5、判断token是否过期
     * @param
     * @return
     */
    public boolean isTokenValid(String token, UserDetails userDetails) {
        // 从token中获取用户名
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername())) &&!isTokenExpired(token);
    }

    /**
     * 6、验证token是否过期
     * @param token
     * @return
     */
    private boolean isTokenExpired(String token) {
        return extractExpiration(token).before(new Date());
    }
    /**
     * 6.1、从授权信息中获取token过期时间
     */
    public Date extractExpiration(String token) {
        return extractClaim(token, Claims::getExpiration);
    }
}
