package dev.lions.unionflow.client.security;

import dev.lions.unionflow.server.api.dto.auth.response.LoginResponse;
import jakarta.enterprise.context.SessionScoped;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.logging.Logger;

@Named("jwtTokenManager")
@SessionScoped
public class JwtTokenManager implements Serializable {
    
    private static final Logger LOGGER = Logger.getLogger(JwtTokenManager.class.getName());
    
    @Inject
    private TokenRefreshService tokenRefreshService;
    
    private String accessToken;
    private String refreshToken;
    private LocalDateTime expirationDate;
    private String tokenType = "Bearer";
    
    public void setTokens(LoginResponse loginResponse) {
        this.accessToken = loginResponse.getAccessToken();
        this.refreshToken = loginResponse.getRefreshToken();
        this.expirationDate = loginResponse.getExpirationDate();
        this.tokenType = loginResponse.getTokenType();
        
        // Enregistrer le token dans le service global
        String sessionId = getSessionId();
        if (sessionId != null) {
            tokenRefreshService.registerToken(sessionId, 
                                            this.accessToken, 
                                            this.refreshToken, 
                                            loginResponse.getExpiresIn());
        }
        
        LOGGER.info("Tokens JWT mis à jour. Expiration: " + expirationDate);
    }
    
    public String getAccessToken() {
        return accessToken;
    }
    
    public String getRefreshToken() {
        return refreshToken;
    }
    
    public String getAuthorizationHeader() {
        if (accessToken != null) {
            return tokenType + " " + accessToken;
        }
        return null;
    }
    
    public boolean isTokenValid() {
        if (accessToken == null || expirationDate == null) {
            return false;
        }
        
        // Considérer le token comme expiré 30 secondes avant l'expiration réelle
        LocalDateTime expirationWithBuffer = expirationDate.minusSeconds(30);
        return LocalDateTime.now().isBefore(expirationWithBuffer);
    }
    
    public boolean needsRefresh() {
        if (accessToken == null || expirationDate == null) {
            return false;
        }
        
        // Rafraîchir le token 5 minutes avant l'expiration
        LocalDateTime refreshThreshold = expirationDate.minusMinutes(5);
        return LocalDateTime.now().isAfter(refreshThreshold);
    }
    
    public long getTimeUntilExpiration() {
        if (expirationDate == null) {
            return 0;
        }
        
        LocalDateTime now = LocalDateTime.now();
        if (now.isAfter(expirationDate)) {
            return 0;
        }
        
        return java.time.Duration.between(now, expirationDate).getSeconds();
    }
    
    public void clearTokens() {
        this.accessToken = null;
        this.refreshToken = null;
        this.expirationDate = null;
        
        // Supprimer le token du service global
        String sessionId = getSessionId();
        if (sessionId != null) {
            tokenRefreshService.removeToken(sessionId);
        }
        
        LOGGER.info("Tokens JWT supprimés");
    }
    
    private String getSessionId() {
        try {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            if (facesContext != null && facesContext.getExternalContext() != null) {
                return facesContext.getExternalContext().getSessionId(false);
            }
        } catch (Exception e) {
            LOGGER.fine("Impossible de récupérer l'ID de session: " + e.getMessage());
        }
        return null;
    }
    
    public boolean hasValidTokens() {
        return accessToken != null && refreshToken != null && isTokenValid();
    }
    
    public LocalDateTime getExpirationDate() {
        return expirationDate;
    }
    
    public String getTokenType() {
        return tokenType;
    }
}
