package com.gbcm.client.beans.auth;

import io.quarkus.oidc.IdToken;
import io.quarkus.oidc.OidcSession;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.enterprise.context.SessionScoped;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Set;

/**
 * Bean JSF pour la gestion de l'authentification OIDC avec Keycloak
 * 
 * @author GBCM Team
 * @version 1.0.0
 * @since 2025-01-01
 */
@Named("authBean")
@SessionScoped
public class AuthBean implements Serializable {
    
    private static final Logger logger = LoggerFactory.getLogger(AuthBean.class);
    
    @Inject
    SecurityIdentity securityIdentity;
    
    @Inject
    OidcSession oidcSession;
    
    @Inject
    @IdToken
    JsonWebToken idToken;
    
    /**
     * Vérifie si l'utilisateur est authentifié
     * 
     * @return true si authentifié
     */
    public boolean isAuthenticated() {
        boolean authenticated = securityIdentity != null && !securityIdentity.isAnonymous();
        logger.debug("Vérification authentification: {}", authenticated);
        return authenticated;
    }
    
    /**
     * Récupère le nom de l'utilisateur connecté
     * 
     * @return Nom d'utilisateur ou null
     */
    public String getUsername() {
        if (isAuthenticated()) {
            String username = securityIdentity.getPrincipal().getName();
            logger.debug("Nom d'utilisateur: {}", username);
            return username;
        }
        return null;
    }
    
    /**
     * Récupère l'email de l'utilisateur connecté
     * 
     * @return Email ou null
     */
    public String getEmail() {
        if (isAuthenticated() && idToken != null) {
            String email = idToken.getClaim("email");
            logger.debug("Email utilisateur: {}", email);
            return email;
        }
        return getUsername(); // Fallback sur le username
    }
    
    /**
     * Récupère le nom complet de l'utilisateur
     * 
     * @return Nom complet ou null
     */
    public String getFullName() {
        if (isAuthenticated() && idToken != null) {
            String firstName = idToken.getClaim("given_name");
            String lastName = idToken.getClaim("family_name");
            
            if (firstName != null && lastName != null) {
                return firstName + " " + lastName;
            } else if (firstName != null) {
                return firstName;
            } else if (lastName != null) {
                return lastName;
            }
        }
        return getUsername(); // Fallback sur le username
    }
    
    /**
     * Récupère les rôles de l'utilisateur
     * 
     * @return Set des rôles
     */
    public Set<String> getRoles() {
        if (isAuthenticated()) {
            Set<String> roles = securityIdentity.getRoles();
            logger.debug("Rôles utilisateur: {}", roles);
            return roles;
        }
        return Set.of();
    }
    
    /**
     * Vérifie si l'utilisateur a un rôle spécifique
     * 
     * @param role Rôle à vérifier
     * @return true si l'utilisateur a le rôle
     */
    public boolean hasRole(String role) {
        boolean hasRole = isAuthenticated() && securityIdentity.hasRole(role);
        logger.debug("Vérification rôle '{}': {}", role, hasRole);
        return hasRole;
    }
    
    /**
     * Vérifie si l'utilisateur est administrateur
     * 
     * @return true si admin
     */
    public boolean isAdmin() {
        return hasRole("ADMIN");
    }
    
    /**
     * Vérifie si l'utilisateur est manager
     * 
     * @return true si manager
     */
    public boolean isManager() {
        return hasRole("MANAGER");
    }
    
    /**
     * Vérifie si l'utilisateur est coach
     * 
     * @return true si coach
     */
    public boolean isCoach() {
        return hasRole("COACH");
    }
    
    /**
     * Vérifie si l'utilisateur est client
     * 
     * @return true si client
     */
    public boolean isClient() {
        return hasRole("CLIENT");
    }
    
    /**
     * Vérifie si l'utilisateur est prospect
     * 
     * @return true si prospect
     */
    public boolean isProspect() {
        return hasRole("PROSPECT");
    }
    
    /**
     * Initie la connexion OIDC
     * 
     * @return Navigation vers la page de login Keycloak
     */
    public String login() {
        logger.info("Initiation de la connexion OIDC");
        // Quarkus OIDC redirigera automatiquement vers Keycloak
        return "/gbcm/login?faces-redirect=true";
    }
    
    /**
     * Déconnexion OIDC
     * 
     * @return Navigation vers la page d'accueil
     */
    public String logout() {
        try {
            logger.info("Déconnexion OIDC pour l'utilisateur: {}", getUsername());
            
            if (oidcSession != null) {
                oidcSession.logout().await().indefinitely();
            }
            
            // Invalider la session JSF
            FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
            
            // Message de confirmation
            FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Déconnexion réussie", 
                    "Vous avez été déconnecté avec succès."));
            
            logger.info("Déconnexion OIDC terminée");
            return "/index?faces-redirect=true";
            
        } catch (Exception e) {
            logger.error("Erreur lors de la déconnexion OIDC", e);
            FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur de déconnexion", 
                    "Une erreur s'est produite lors de la déconnexion."));
            return null;
        }
    }
    
    /**
     * Récupère l'URL de déconnexion Keycloak
     * 
     * @return URL de déconnexion
     */
    public String getLogoutUrl() {
        return "http://localhost:8180/realms/gbcm-llc/protocol/openid-connect/logout" +
               "?redirect_uri=http://localhost:8081/gbcm/";
    }
    
    /**
     * Récupère des informations sur le token ID
     * 
     * @return Informations du token ou message d'erreur
     */
    public String getTokenInfo() {
        if (idToken != null) {
            return "Token émis par: " + idToken.getIssuer() + 
                   ", Expire à: " + idToken.getExpirationTime();
        }
        return "Aucun token ID disponible";
    }
}
