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

import dev.lions.user.manager.client.service.RoleServiceClient;
import dev.lions.user.manager.dto.role.RoleAssignmentDTO;
import dev.lions.user.manager.dto.role.RoleDTO;
import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.enums.role.TypeRole;
import jakarta.annotation.PostConstruct;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import lombok.Data;
import org.eclipse.microprofile.rest.client.inject.RestClient;

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

/**
 * Bean JSF pour la gestion des rôles
 * 
 * @author Lions User Manager
 * @version 1.0.0
 */
@Named("roleGestionBean")
@ViewScoped
@Data
public class RoleGestionBean implements Serializable {

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

    @Inject
    @RestClient
    private RoleServiceClient roleServiceClient;

    // Liste des rôles
    private List<RoleDTO> realmRoles = new ArrayList<>();
    private List<RoleDTO> clientRoles = new ArrayList<>();
    private List<RoleDTO> allRoles = new ArrayList<>();
    private RoleDTO selectedRole;

    // Pour la création/édition
    private RoleDTO newRole = RoleDTO.builder().build();
    private boolean editMode = false;

    // Filtres
    private String realmName = "master";
    private String clientName;
    private TypeRole selectedTypeRole;
    private String roleSearchText;

    // Options
    private List<TypeRole> typeRoleOptions = List.of(TypeRole.values());
    private List<String> availableRealms = new ArrayList<>();
    private List<String> availableClients = new ArrayList<>();

    @PostConstruct
    public void init() {
        loadRealms();
        loadRealmRoles();
    }

    /**
     * Charger les rôles Realm
     */
    public void loadRealmRoles() {
        if (realmName == null || realmName.isEmpty()) {
            LOGGER.warning("Realm non sélectionné, impossible de charger les rôles");
            addErrorMessage("Veuillez sélectionner un realm");
            return;
        }
        
        try {
            LOGGER.info("Chargement des rôles Realm pour le realm: " + realmName);
            realmRoles = roleServiceClient.getAllRealmRoles(realmName);
            updateAllRoles();
            LOGGER.info("Chargement réussi: " + realmRoles.size() + " rôles Realm trouvés");
            if (realmRoles.isEmpty()) {
                addErrorMessage("Aucun rôle Realm trouvé dans le realm: " + realmName);
            }
        } catch (Exception e) {
            String errorMsg = "Erreur lors du chargement des rôles Realm pour le realm '" + realmName + "': " + e.getMessage();
            LOGGER.severe(errorMsg);
            LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e);
            addErrorMessage(errorMsg);
            realmRoles = new ArrayList<>(); // Réinitialiser en cas d'erreur
            updateAllRoles();
        }
    }

    /**
     * Charger les rôles Client
     */
    public void loadClientRoles() {
        if (clientName == null || clientName.isEmpty()) {
            return;
        }

        try {
            clientRoles = roleServiceClient.getAllClientRoles(realmName, clientName);
            updateAllRoles();
            LOGGER.info("Chargement de " + clientRoles.size() + " rôles Client");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des rôles Client: " + e.getMessage());
            addErrorMessage("Erreur lors du chargement des rôles Client");
        }
    }

    /**
     * Mettre à jour la liste complète des rôles
     */
    private void updateAllRoles() {
        allRoles = new ArrayList<>();
        allRoles.addAll(realmRoles);
        allRoles.addAll(clientRoles);
    }

    /**
     * Créer un nouveau rôle Realm
     */
    public void createRealmRole() {
        try {
            RoleDTO created = roleServiceClient.createRealmRole(newRole, realmName);
            addSuccessMessage("Rôle Realm créé avec succès: " + created.getName());
            resetForm();
            loadRealmRoles();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la création: " + e.getMessage());
            addErrorMessage("Erreur lors de la création: " + e.getMessage());
        }
    }

    /**
     * Créer un nouveau rôle Client
     */
    public void createClientRole() {
        if (clientName == null || clientName.isEmpty()) {
            addErrorMessage("Le nom du client est obligatoire");
            return;
        }

        try {
            RoleDTO created = roleServiceClient.createClientRole(newRole, realmName, clientName);
            addSuccessMessage("Rôle Client créé avec succès: " + created.getName());
            resetForm();
            loadClientRoles();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la création: " + e.getMessage());
            addErrorMessage("Erreur lors de la création: " + e.getMessage());
        }
    }

    /**
     * Supprimer un rôle Realm
     */
    public void deleteRealmRole(String roleName) {
        try {
            roleServiceClient.deleteRealmRole(roleName, realmName);
            addSuccessMessage("Rôle Realm supprimé avec succès");
            loadRealmRoles();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la suppression: " + e.getMessage());
            addErrorMessage("Erreur lors de la suppression: " + e.getMessage());
        }
    }

    /**
     * Supprimer un rôle Client
     */
    public void deleteClientRole(String roleName) {
        if (clientName == null || clientName.isEmpty()) {
            addErrorMessage("Le nom du client est obligatoire");
            return;
        }

        try {
            roleServiceClient.deleteClientRole(roleName, realmName, clientName);
            addSuccessMessage("Rôle Client supprimé avec succès");
            loadClientRoles();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la suppression: " + e.getMessage());
            addErrorMessage("Erreur lors de la suppression: " + e.getMessage());
        }
    }

    /**
     * Attribuer un rôle à un utilisateur
     */
    public void assignRoleToUser(String userId, String roleName) {
        try {
            RoleAssignmentDTO assignment = RoleAssignmentDTO.builder()
                .userId(userId)
                .roleNames(List.of(roleName))
                .typeRole(TypeRole.REALM_ROLE)
                .realmName(realmName)
                .build();

            roleServiceClient.assignRoleToUser(assignment);
            addSuccessMessage("Rôle attribué avec succès");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'attribution: " + e.getMessage());
            addErrorMessage("Erreur lors de l'attribution: " + e.getMessage());
        }
    }

    /**
     * Révoquer un rôle d'un utilisateur
     */
    public void revokeRoleFromUser(String userId, String roleName) {
        try {
            RoleAssignmentDTO assignment = RoleAssignmentDTO.builder()
                .userId(userId)
                .roleNames(List.of(roleName))
                .typeRole(TypeRole.REALM_ROLE)
                .realmName(realmName)
                .build();

            roleServiceClient.revokeRoleFromUser(assignment);
            addSuccessMessage("Rôle révoqué avec succès");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la révocation: " + e.getMessage());
            addErrorMessage("Erreur lors de la révocation: " + e.getMessage());
        }
    }

    /**
     * Attribuer un rôle à un utilisateur (depuis les paramètres de requête)
     */
    public void assignRoleFromParams() {
        FacesContext context = FacesContext.getCurrentInstance();
        String userId = context.getExternalContext().getRequestParameterMap().get("userId");
        String roleName = context.getExternalContext().getRequestParameterMap().get("roleName");
        
        if (userId != null && roleName != null) {
            assignRoleToUser(userId, roleName);
        } else {
            addErrorMessage("Paramètres manquants: userId ou roleName");
        }
    }

    /**
     * Révoquer un rôle d'un utilisateur (depuis les paramètres de requête)
     */
    public void revokeRoleFromParams() {
        FacesContext context = FacesContext.getCurrentInstance();
        String userId = context.getExternalContext().getRequestParameterMap().get("userId");
        String roleName = context.getExternalContext().getRequestParameterMap().get("roleName");
        
        if (userId != null && roleName != null) {
            revokeRoleFromUser(userId, roleName);
        } else {
            addErrorMessage("Paramètres manquants: userId ou roleName");
        }
    }

    /**
     * Obtenir les rôles RoleDTO correspondant aux noms de rôles de l'utilisateur
     */
    public List<RoleDTO> getUserRolesDTOs(UserDTO user) {
        if (user == null || user.getRealmRoles() == null || user.getRealmRoles().isEmpty()) {
            return new ArrayList<>();
        }
        
        if (allRoles == null || allRoles.isEmpty()) {
            return new ArrayList<>();
        }
        
        return allRoles.stream()
            .filter(role -> user.getRealmRoles().contains(role.getName()))
            .collect(java.util.stream.Collectors.toList());
    }

    /**
     * Réinitialiser le formulaire
     */
    public void resetForm() {
        newRole = RoleDTO.builder().build();
        editMode = false;
    }

    /**
     * Charger les realms disponibles
     */
    private void loadRealms() {
        try {
            // Pour l'instant, utiliser les realms de la configuration
            // TODO: Implémenter la récupération des realms depuis Keycloak via un endpoint API
            availableRealms = List.of("master", "lions-user-manager", "btpxpress", "test-realm");
            LOGGER.info("Realms disponibles chargés: " + availableRealms.size());
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des realms: " + e.getMessage());
            // Fallback sur une liste par défaut
            availableRealms = List.of("master");
        }
    }

    // Méthodes utilitaires
    private void addSuccessMessage(String message) {
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message));
    }

    private void addErrorMessage(String message) {
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message));
    }
}

