content: package com.back2reality.security;
  
  import com.back2reality.storage.entities.User;
  import io.jsonwebtoken.Claims;
  import io.jsonwebtoken.Jwts;
  import io.jsonwebtoken.SignatureAlgorithm;
  import io.jsonwebtoken.io.Decoders;
  import io.jsonwebtoken.security.Keys;
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.security.core.userdetails.UserDetails;
  
  import java.security.Key;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.function.Function;
  
  /**
   * @author FLIGHT
   */
  public class JwtService {
  
    @Value("${security.key}")
    private String jwtSigningKey;
  
    @Value("${security.token.expiration_days}")
    private long tokenExpirationDays;
  
    public String extractUserName(String token) {
      return extractClaim(token, Claims::getSubject);
    }
  
    public String generateToken(UserDetails userDetails) {
      Map<String, Object> claims = new HashMap<>();
      if (userDetails instanceof User customUserDetails) {
        claims.put("id", customUserDetails.getId());
        claims.put("email", customUserDetails.getEmail());
        claims.put("role", customUserDetails.getRole());
      }
      return generateToken(claims, userDetails);
    }
  
    public boolean isTokenValid(String token, UserDetails userDetails) {
      final String userName = extractUserName(token);
      return (userName.equals(userDetails.getUsername())) && !isTokenExpired(token);
    }
  
    private <T> T extractClaim(String token, Function<Claims, T> claimsResolvers) {
      final Claims claims = extractAllClaims(token);
      return claimsResolvers.apply(claims);
    }
  
  
    private String generateToken(Map<String, Object> extraClaims, UserDetails userDetails) {
      return Jwts.builder().claims(extraClaims)
        .subject(userDetails.getUsername())
        .issuedAt(new Date(System.currentTimeMillis()))
        .expiration(new Date(System.currentTimeMillis() + 100000 * 60 * 24 * tokenExpirationDays))
        .signWith(getSigningKey(), SignatureAlgorithm.HS256)
        .compact();
    }
  
    private boolean isTokenExpired(String token) {
      return extractExpiration(token).before(new Date());
    }
  
    private Date extractExpiration(String token) {
      return extractClaim(token, Claims::getExpiration);
    }
  
    private Claims extractAllClaims(String token) {
      return Jwts.parser()
        .setSigningKey(getSigningKey())
        .build()
        .parseClaimsJws(token)
        .getBody();
    }
  
    private Key getSigningKey() {
      byte[] keyBytes = Decoders.BASE64.decode(jwtSigningKey);
      return Keys.hmacShaKeyFor(keyBytes);
    }
  }
  