package dev.lions.user.manager.client.view;

import io.quarkus.oidc.IdToken;
import io.quarkus.oidc.OidcSession;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.SessionScoped;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import lombok.Data;
import org.eclipse.microprofile.jwt.JsonWebToken;

import java.io.Serializable;
import java.util.logging.Logger;

/**
 * Bean de session pour gérer les informations de l'utilisateur connecté
 * 
 * @author Lions User Manager
 * @version 1.0.0
 */
@Named("userSessionBean")
@SessionScoped
@Data
public class UserSessionBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger LOGGER = Logger.getLogger(UserSessionBean.class.getName());

    @Inject
    SecurityIdentity securityIdentity;

    @Inject
    @IdToken
    JsonWebToken idToken;

    @Inject
    OidcSession oidcSession;

    // Informations utilisateur
    private String username;
    private String email;
    private String firstName;
    private String lastName;
    private String fullName;
    private String initials;

    @PostConstruct
    public void init() {
        loadUserInfo();
    }

    /**
     * Charger les informations utilisateur depuis le token OIDC
     */
    public void loadUserInfo() {
        try {
            if (idToken != null && securityIdentity != null && !securityIdentity.isAnonymous()) {
                // Username
                username = idToken.getClaim("preferred_username");
                if (username == null || username.trim().isEmpty()) {
                    username = securityIdentity.getPrincipal().getName();
                }

                // Email
                email = idToken.getClaim("email");
                if (email == null || email.trim().isEmpty()) {
                    email = username + "@lions.dev";
                }

                // Prénom et nom
                firstName = idToken.getClaim("given_name");
                lastName = idToken.getClaim("family_name");

                // Nom complet
                fullName = idToken.getClaim("name");
                if (fullName == null || fullName.trim().isEmpty()) {
                    if (firstName != null && lastName != null) {
                        fullName = firstName + " " + lastName;
                    } else if (firstName != null) {
                        fullName = firstName;
                    } else if (lastName != null) {
                        fullName = lastName;
                    } else {
                        fullName = username;
                    }
                }

                // Initiales pour l'avatar
                initials = generateInitials(fullName);

                LOGGER.info("Informations utilisateur chargées: " + fullName + " (" + email + ")");
            } else {
                // Valeurs par défaut si non authentifié
                username = "Utilisateur";
                email = "utilisateur@lions.dev";
                fullName = "Utilisateur";
                initials = "U";
            }
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des informations utilisateur: " + e.getMessage());
            username = "Utilisateur";
            email = "utilisateur@lions.dev";
            fullName = "Utilisateur";
            initials = "U";
        }
    }

    /**
     * Générer les initiales depuis le nom complet
     */
    private String generateInitials(String name) {
        if (name == null || name.trim().isEmpty()) {
            return "U";
        }

        String[] parts = name.trim().split("\\s+");
        if (parts.length >= 2) {
            return String.valueOf(parts[0].charAt(0)).toUpperCase() +
                    String.valueOf(parts[1].charAt(0)).toUpperCase();
        } else if (parts.length == 1) {
            String part = parts[0];
            if (part.length() >= 2) {
                return part.substring(0, 2).toUpperCase();
            } else {
                return part.substring(0, 1).toUpperCase();
            }
        }
        return "U";
    }

    // Rôles
    private java.util.Set<String> roles;
    private String primaryRole;

    /**
     * Obtenir le rôle principal de l'utilisateur
     */
    public String getPrimaryRole() {
        if (primaryRole == null) {
            primaryRole = getMainRole();
        }
        return primaryRole;
    }

    /**
     * Obtenir tous les rôles de l'utilisateur
     */
    public java.util.Set<String> getRoles() {
        if (roles == null) {
            roles = new java.util.HashSet<>();
            try {
                if (securityIdentity != null && securityIdentity.getRoles() != null) {
                    roles.addAll(securityIdentity.getRoles());
                }
            } catch (Exception e) {
                LOGGER.warning("Erreur lors de la récupération des rôles: " + e.getMessage());
            }
            if (roles.isEmpty()) {
                roles.add("Utilisateur");
            }
        }
        return roles;
    }

    /**
     * Obtenir le rôle principal de l'utilisateur (méthode interne)
     */
    private String getMainRole() {
        try {
            if (securityIdentity != null && securityIdentity.getRoles() != null
                    && !securityIdentity.getRoles().isEmpty()) {
                // Prioriser certains rôles
                java.util.Set<String> roleSet = securityIdentity.getRoles();
                if (roleSet.contains("admin")) {
                    return "Administrateur";
                } else if (roleSet.contains("user_manager")) {
                    return "Gestionnaire";
                } else if (roleSet.contains("user_viewer")) {
                    return "Consultant";
                } else {
                    return roleSet.iterator().next();
                }
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la récupération du rôle: " + e.getMessage());
        }
        return "Utilisateur";
    }

    /**
     * Vérifier si l'utilisateur est authentifié
     */
    public boolean isAuthenticated() {
        return securityIdentity != null && !securityIdentity.isAnonymous();
    }

    /**
     * Vérifier si l'utilisateur a un rôle spécifique
     */
    public boolean hasRole(String role) {
        try {
            if (securityIdentity != null && securityIdentity.getRoles() != null) {
                return securityIdentity.getRoles().contains(role);
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la vérification du rôle: " + e.getMessage());
        }
        return false;
    }

    /**
     * Obtenir l'issuer du token OIDC
     */
    public String getIssuer() {
        try {
            if (idToken != null) {
                return idToken.getIssuer();
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la récupération de l'issuer: " + e.getMessage());
        }
        return "Non disponible";
    }

    /**
     * Obtenir le subject du token OIDC
     */
    public String getSubject() {
        try {
            if (idToken != null) {
                return idToken.getSubject();
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la récupération du subject: " + e.getMessage());
        }
        return "Non disponible";
    }

    /**
     * Obtenir le session ID
     */
    public String getSessionId() {
        try {
            if (idToken != null) {
                Object sid = idToken.getClaim("sid");
                if (sid != null) {
                    return sid.toString();
                }
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la récupération du session ID: " + e.getMessage());
        }
        return "Non disponible";
    }

    /**
     * Obtenir le temps d'expiration du token
     */
    public java.util.Date getExpirationTime() {
        try {
            if (idToken != null && idToken.getExpirationTime() > 0) {
                return new java.util.Date(idToken.getExpirationTime() * 1000L);
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la récupération de l'expiration: " + e.getMessage());
        }
        return null;
    }

    /**
     * Obtenir le temps d'émission du token
     */
    public java.util.Date getIssuedAt() {
        try {
            if (idToken != null && idToken.getIssuedAtTime() > 0) {
                return new java.util.Date(idToken.getIssuedAtTime() * 1000L);
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la récupération de l'émission: " + e.getMessage());
        }
        return null;
    }

    /**
     * Obtenir l'audience du token
     */
    public String getAudience() {
        try {
            if (idToken != null && idToken.getAudience() != null && !idToken.getAudience().isEmpty()) {
                return String.join(", ", idToken.getAudience());
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la récupération de l'audience: " + e.getMessage());
        }
        return "Non disponible";
    }

    /**
     * Obtenir l'authorized party (azp)
     */
    public String getAuthorizedParty() {
        try {
            if (idToken != null) {
                Object azp = idToken.getClaim("azp");
                if (azp != null) {
                    return azp.toString();
                }
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la récupération de l'authorized party: " + e.getMessage());
        }
        return "Non disponible";
    }

    /**
     * Vérifier si l'email est vérifié
     */
    public boolean isEmailVerified() {
        try {
            if (idToken != null) {
                Boolean emailVerified = idToken.getClaim("email_verified");
                return emailVerified != null && emailVerified;
            }
        } catch (Exception e) {
            LOGGER.warning("Erreur lors de la vérification de l'email: " + e.getMessage());
        }
        return false;
    }

    /**
     * Déconnexion OIDC
     * Redirige vers l'endpoint de logout Quarkus qui gère la déconnexion Keycloak
     */
    public String logout() {
        try {
            LOGGER.info("Déconnexion de l'utilisateur: " + fullName);

            FacesContext facesContext = FacesContext.getCurrentInstance();
            ExternalContext externalContext = facesContext.getExternalContext();

            // Invalider la session HTTP locale
            externalContext.invalidateSession();

            // Rediriger vers l'endpoint de logout OIDC de Quarkus
            // Quarkus gère la déconnexion Keycloak (end_session_endpoint) + redirection
            // post-logout
            String contextPath = externalContext.getRequestContextPath();
            externalContext.redirect(contextPath + "/auth/logout");
            facesContext.responseComplete();

            return null;
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la déconnexion: " + e.getMessage());
            // En cas d'erreur, rediriger vers la page d'accueil
            return "/?faces-redirect=true";
        }
    }
}
