// Path: spat-services/src/main/java/com/pcalouche/spat/config/SpatProperties.java
// @Getter
// @Setter
// @Component
// @ConfigurationProperties(prefix = "spat")
// @Validated
// public class SpatProperties {
//     /**
//      * The current version. This is set use Spring Boot's automatic
//      * property expansion.
//      */
//     private String version;
//     /**
//      * What origins to allow access from
//      */
//     private String[] corsAllowedOrigins;
//     /**
//      * The signing key used for JWTs.
//      */
//     @NotEmpty
//     private String jwtSigningKey;
//     /**
//      * How long JWT tokens are good for
//      */
//     @NonNull
//     private Duration jwtTokenDuration;
//     /**
//      * How long JWT refresh tokens are good for
//      */
//     @NotNull
//     private Duration refreshTokenDuration;
//     /**
//      * The hostname of the environment
//      */
//     @NotEmpty
//     private String hostname;
// 
//     public boolean isHttpsEnvironment() {
//         return !"localhost".equals(hostname);
//     }
// }
// 
// Path: spat-services/src/main/java/com/pcalouche/spat/entity/User.java
// @Entity
// @Table(name = "users")
// @Getter
// @Setter
// @Builder
// @NoArgsConstructor
// @AllArgsConstructor
// public class User implements UserDetails {
//     @Id
//     @GeneratedValue(strategy = GenerationType.IDENTITY)
//     private Integer id;
//     @NotBlank
//     @Column(unique = true, nullable = false)
//     private String username;
//     @NotBlank
//     @Column(nullable = false)
//     private String password;
//     @Builder.Default
//     private boolean accountNonExpired = true;
//     @Builder.Default
//     private boolean accountNonLocked = true;
//     @Builder.Default
//     private boolean credentialsNonExpired = true;
//     @Builder.Default
//     private boolean enabled = true;
//     @ManyToMany(fetch = FetchType.EAGER)
//     @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
//     @Builder.Default
//     private Set<Role> roles = new HashSet<>();
//     @Transient
//     @Setter(AccessLevel.NONE)
//     private Set<SimpleGrantedAuthority> authorities;
// 
//     @Override
//     public Set<SimpleGrantedAuthority> getAuthorities() {
//         if (authorities == null) {
//             authorities = new HashSet<>();
//             if (roles != null) {
//                 for (Role role : roles) {
//                     authorities.add(new SimpleGrantedAuthority(role.getName()));
//                 }
//             }
//         }
//         return authorities;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) {
//             return true;
//         }
//         if (!(o instanceof User)) {
//             return false;
//         }
//         User castedObj = (User) o;
//         return Objects.equals(username, castedObj.getUsername());
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(username);
//     }
// }


import com.pcalouche.spat.config.SpatProperties;
import com.pcalouche.spat.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
        if (spatProperties.getJwtTokenDuration().compareTo(spatProperties.getRefreshTokenDuration()) > 0) {
            throw new IllegalArgumentException("jwt token duration cannot be greater than refresh token duration");
        }
        this.spatProperties = spatProperties;
        this.secretKey = Keys.hmacShaKeyFor(SIGNING_KEY.getBytes());
    }

    public static String[] getDecodedBasicAuthFromRequest(HttpServletRequest request) throws AuthenticationException {
        String headerValue = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (headerValue != null && headerValue.startsWith(AUTH_HEADER_BASIC_PREFIX)) {
            String encodedBase64String = headerValue.replace(AUTH_HEADER_BASIC_PREFIX, "");
            String[] decodedBasicAuthorizationParts = new String(Base64.getDecoder().decode(encodedBase64String)).split(":");
            if (decodedBasicAuthorizationParts.length != 2) {
                throw new BadCredentialsException("Basic Authentication header is invalid");
            } else {
                return decodedBasicAuthorizationParts;
            }
        } else {
            throw new BadCredentialsException("Basic Authentication header is invalid");
        }
    }

    public static String getTokenFromRequest(HttpServletRequest request) {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (token != null && token.startsWith(AUTH_HEADER_BEARER_PREFIX)) {
            token = token.replace(AUTH_HEADER_BEARER_PREFIX, "");
        }
        return token;
    }

// Path: spat-services/src/main/java/com/pcalouche/spat/config/SpatProperties.java
// @Getter
// @Setter
// @Component
// @ConfigurationProperties(prefix = "spat")
// @Validated
// public class SpatProperties {
//     /**
//      * The current version. This is set use Spring Boot's automatic
//      * property expansion.
//      */
//     private String version;
//     /**
//      * What origins to allow access from
//      */
//     private String[] corsAllowedOrigins;
//     /**
//      * The signing key used for JWTs.
//      */
//     @NotEmpty
//     private String jwtSigningKey;
//     /**
//      * How long JWT tokens are good for
//      */
//     @NonNull
//     private Duration jwtTokenDuration;
//     /**
//      * How long JWT refresh tokens are good for
//      */
//     @NotNull
//     private Duration refreshTokenDuration;
//     /**
//      * The hostname of the environment
//      */
//     @NotEmpty
//     private String hostname;
// 
//     public boolean isHttpsEnvironment() {
//         return !"localhost".equals(hostname);
//     }
// }
// 
// Path: spat-services/src/main/java/com/pcalouche/spat/entity/User.java
// @Entity
// @Table(name = "users")
// @Getter
// @Setter
// @Builder
// @NoArgsConstructor
// @AllArgsConstructor
// public class User implements UserDetails {
//     @Id
//     @GeneratedValue(strategy = GenerationType.IDENTITY)
//     private Integer id;
//     @NotBlank
//     @Column(unique = true, nullable = false)
//     private String username;
//     @NotBlank
//     @Column(nullable = false)
//     private String password;
//     @Builder.Default
//     private boolean accountNonExpired = true;
//     @Builder.Default
//     private boolean accountNonLocked = true;
//     @Builder.Default
//     private boolean credentialsNonExpired = true;
//     @Builder.Default
//     private boolean enabled = true;
//     @ManyToMany(fetch = FetchType.EAGER)
//     @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
//     @Builder.Default
//     private Set<Role> roles = new HashSet<>();
//     @Transient
//     @Setter(AccessLevel.NONE)
//     private Set<SimpleGrantedAuthority> authorities;
// 
//     @Override
//     public Set<SimpleGrantedAuthority> getAuthorities() {
//         if (authorities == null) {
//             authorities = new HashSet<>();
//             if (roles != null) {
//                 for (Role role : roles) {
//                     authorities.add(new SimpleGrantedAuthority(role.getName()));
//                 }
//             }
//         }
//         return authorities;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) {
//             return true;
//         }
//         if (!(o instanceof User)) {
//             return false;
//         }
//         User castedObj = (User) o;
//         return Objects.equals(username, castedObj.getUsername());
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(username);
//     }
// }


// Path: spat-services/src/main/java/com/pcalouche/spat/security/util/SecurityUtils.java
import com.pcalouche.spat.config.SpatProperties;
import com.pcalouche.spat.entity.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

        if (spatProperties.getJwtTokenDuration().compareTo(spatProperties.getRefreshTokenDuration()) > 0) {
            throw new IllegalArgumentException("jwt token duration cannot be greater than refresh token duration");
        }
        this.spatProperties = spatProperties;
        this.secretKey = Keys.hmacShaKeyFor(SIGNING_KEY.getBytes());
    }

    public static String[] getDecodedBasicAuthFromRequest(HttpServletRequest request) throws AuthenticationException {
        String headerValue = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (headerValue != null && headerValue.startsWith(AUTH_HEADER_BASIC_PREFIX)) {
            String encodedBase64String = headerValue.replace(AUTH_HEADER_BASIC_PREFIX, "");
            String[] decodedBasicAuthorizationParts = new String(Base64.getDecoder().decode(encodedBase64String)).split(":");
            if (decodedBasicAuthorizationParts.length != 2) {
                throw new BadCredentialsException("Basic Authentication header is invalid");
            } else {
                return decodedBasicAuthorizationParts;
            }
        } else {
            throw new BadCredentialsException("Basic Authentication header is invalid");
        }
    }

    public static String getTokenFromRequest(HttpServletRequest request) {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (token != null && token.startsWith(AUTH_HEADER_BEARER_PREFIX)) {
            token = token.replace(AUTH_HEADER_BEARER_PREFIX, "");
        }
        return token;
    }

    public static void validateUserAccountStatus(User user) {