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

import dev.lions.user.manager.client.service.RealmServiceClient;
import dev.lions.user.manager.client.service.UserServiceClient;
import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.dto.user.UserSearchCriteriaDTO;
import dev.lions.user.manager.dto.user.UserSearchResultDTO;
import dev.lions.user.manager.enums.user.StatutUser;
import jakarta.annotation.PostConstruct;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.event.ActionEvent;
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 org.primefaces.event.data.PageEvent;

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

/**
 * Bean JSF pour la liste et la recherche d'utilisateurs
 * 
 * @author Lions User Manager
 * @version 1.0.0
 */
@Named("userListBean")
@ViewScoped
@Data
public class UserListBean implements Serializable {

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

    // Constantes de navigation outcomes (WOU/DRY - réutilisables)
    private static final String OUTCOME_USER_PROFILE = "userProfilePage";
    private static final String OUTCOME_USER_EDIT = "userEditPage";
    private static final String OUTCOME_USER_CREATE = "userCreatePage";

    @Inject
    @RestClient
    private UserServiceClient userServiceClient;

    @Inject
    @RestClient
    private RealmServiceClient realmServiceClient;

    @Inject
    private UserSessionBean userSessionBean;

    // Propriétés pour la liste
    private List<UserDTO> users = new ArrayList<>();
    private UserDTO selectedUser;
    private List<UserDTO> selectedUsers = new ArrayList<>();

    // Propriétés pour la recherche
    private UserSearchCriteriaDTO searchCriteria = UserSearchCriteriaDTO.builder().build();
    private String searchText;
    // Par défaut, utiliser le realm lions-user-manager où les utilisateurs sont configurés
    private String realmName = "lions-user-manager";
    private StatutUser selectedStatut;

    // Propriétés pour la pagination
    private int currentPage = 0;
    private int pageSize = 20;
    private long totalRecords = 0;
    private int totalPages = 0;

    // Options pour les selects
    private List<StatutUser> statutOptions = List.of(StatutUser.values());
    private List<String> availableRealms = new ArrayList<>();

    @PostConstruct
    public void init() {
        LOGGER.info("Initialisation de UserListBean");
        loadUsers();
        loadRealms();
    }

    /**
     * Charger la liste des utilisateurs
     */
    public void loadUsers() {
        try {
            UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                .realmName(realmName)
                .page(currentPage)
                .pageSize(pageSize)
                .build();

            UserSearchResultDTO result = userServiceClient.searchUsers(criteria);
            this.users = result.getUsers() != null ? result.getUsers() : new ArrayList<>();
            this.totalRecords = result.getTotalCount() != null ? result.getTotalCount() : 0;
            this.totalPages = (int) Math.ceil((double) totalRecords / pageSize);

            LOGGER.info("Chargement de " + users.size() + " utilisateurs");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des utilisateurs: " + e.getMessage());
            addErrorMessage("Erreur lors du chargement des utilisateurs: " + e.getMessage());
        }
    }

    /**
     * Rechercher des utilisateurs
     */
    public void search() {
        try {
            currentPage = 0; // Réinitialiser à la première page

            UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder()
                .realmName(realmName)
                .searchTerm(searchText)
                .statut(selectedStatut)
                .page(currentPage)
                .pageSize(pageSize)
                .build();

            UserSearchResultDTO result = userServiceClient.searchUsers(criteria);
            this.users = result.getUsers() != null ? result.getUsers() : new ArrayList<>();
            this.totalRecords = result.getTotalCount() != null ? result.getTotalCount() : 0;
            this.totalPages = (int) Math.ceil((double) totalRecords / pageSize);

            addSuccessMessage("Recherche effectuée: " + totalRecords + " résultat(s) trouvé(s)");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la recherche: " + e.getMessage());
            addErrorMessage("Erreur lors de la recherche: " + e.getMessage());
        }
    }

    /**
     * Réinitialiser la recherche
     */
    public void resetSearch() {
        searchText = null;
        selectedStatut = null;
        currentPage = 0;
        loadUsers();
    }

    /**
     * Gérer les événements de pagination du datatable
     */
    public void onPageChange(PageEvent event) {
        try {
            int page = event.getPage();
            
            currentPage = page;
            
            LOGGER.info("Changement de page: page=" + currentPage + ", rows=" + pageSize);
            
            // Recharger les données avec la nouvelle page
            loadUsers();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du changement de page: " + e.getMessage());
            addErrorMessage("Erreur lors du changement de page: " + e.getMessage());
        }
    }

    /**
     * Action pour activer un utilisateur (utilisé par le composant composite)
     */
    public void activateUserAction(ActionEvent event) {
        String userId = (String) event.getComponent().getAttributes().get("userId");
        if (userId != null) {
            activateUser(userId);
        }
    }

    /**
     * Action pour désactiver un utilisateur (utilisé par le composant composite)
     */
    public void deactivateUserAction(ActionEvent event) {
        String userId = (String) event.getComponent().getAttributes().get("userId");
        if (userId != null) {
            deactivateUser(userId);
        }
    }

    /**
     * Action pour supprimer un utilisateur (utilisé par le composant composite)
     */
    public void deleteUserAction(ActionEvent event) {
        String userId = (String) event.getComponent().getAttributes().get("userId");
        if (userId != null) {
            deleteUser(userId);
        }
    }

    /**
     * Activer un utilisateur
     */
    public void activateUser(String userId) {
        try {
            LOGGER.info("Activation de l'utilisateur: " + userId + " dans le realm: " + realmName);
            userServiceClient.activateUser(userId, realmName);
            addSuccessMessage("Utilisateur activé avec succès");
            // Recharger les données
            loadUsers();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'activation: " + e.getMessage());
            LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e);
            addErrorMessage("Erreur lors de l'activation: " + e.getMessage());
        }
    }

    /**
     * Désactiver un utilisateur
     */
    public void deactivateUser(String userId) {
        try {
            LOGGER.info("Désactivation de l'utilisateur: " + userId + " dans le realm: " + realmName);
            userServiceClient.deactivateUser(userId, realmName);
            addSuccessMessage("Utilisateur désactivé avec succès");
            // Recharger les données
            loadUsers();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la désactivation: " + e.getMessage());
            LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e);
            addErrorMessage("Erreur lors de la désactivation: " + e.getMessage());
        }
    }

    /**
     * Supprimer un utilisateur
     */
    public void deleteUser(String userId) {
        try {
            LOGGER.info("Suppression de l'utilisateur: " + userId + " dans le realm: " + realmName);
            userServiceClient.deleteUser(userId, realmName);
            addSuccessMessage("Utilisateur supprimé avec succès");
            // Recharger les données
            loadUsers();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la suppression: " + e.getMessage());
            LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e);
            addErrorMessage("Erreur lors de la suppression: " + e.getMessage());
        }
    }

    /**
     * Déconnecter toutes les sessions d'un utilisateur
     */
    public void logoutAllSessions(String userId) {
        try {
            userServiceClient.logoutAllSessions(userId, realmName);
            addSuccessMessage("Toutes les sessions ont été déconnectées");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la déconnexion: " + e.getMessage());
            addErrorMessage("Erreur lors de la déconnexion: " + e.getMessage());
        }
    }

    /**
     * Obtenir le nombre d'utilisateurs actifs
     */
    public long getActiveUsersCount() {
        if (users == null || users.isEmpty()) {
            return 0;
        }
        return users.stream()
            .filter(user -> user.getEnabled() != null && user.getEnabled())
            .count();
    }

    /**
     * Obtenir le nombre d'utilisateurs désactivés
     */
    public long getDisabledUsersCount() {
        if (users == null || users.isEmpty()) {
            return 0;
        }
        return users.stream()
            .filter(user -> user.getEnabled() != null && !user.getEnabled())
            .count();
    }

    /**
     * Obtenir le pourcentage d'utilisateurs actifs
     */
    public int getActiveUsersPercentage() {
        if (totalRecords == 0) {
            return 0;
        }
        return (int) Math.round((double) getActiveUsersCount() / totalRecords * 100);
    }

    /**
     * Obtenir le pourcentage d'utilisateurs désactivés
     */
    public int getDisabledUsersPercentage() {
        if (totalRecords == 0) {
            return 0;
        }
        return (int) Math.round((double) getDisabledUsersCount() / totalRecords * 100);
    }

    /**
     * Rafraîchir les données
     */
    public void refreshData() {
        loadUsers();
        addSuccessMessage("Données rafraîchies");
    }

    /**
     * Exporter vers CSV (placeholder)
     */
    public void exportToCSV() {
        addSuccessMessage("Fonctionnalité d'export en cours de développement");
    }

    /**
     * Importer des utilisateurs (placeholder)
     */
    public void importUsers() {
        addSuccessMessage("Fonctionnalité d'import en cours de développement");
    }

    /**
     * Charger les realms disponibles depuis Keycloak en fonction des permissions de l'utilisateur
     */
    private void loadRealms() {
        try {
            // Récupérer tous les realms depuis Keycloak
            List<String> allRealms = realmServiceClient.getAllRealms();
            
            if (allRealms == null || allRealms.isEmpty()) {
                LOGGER.warning("Aucun realm trouvé dans Keycloak");
                availableRealms = Collections.emptyList();
                return;
            }

            List<String> authorizedRealms = userSessionBean.getAuthorizedRealms();

            // Si liste vide, l'utilisateur est super admin (peut gérer tous les realms)
            if (authorizedRealms.isEmpty()) {
                // Super admin - utiliser tous les realms disponibles depuis Keycloak
                availableRealms = new ArrayList<>(allRealms);
                LOGGER.info("Super admin détecté - " + availableRealms.size() + " realms disponibles depuis Keycloak");
            } else {
                // Realm admin - filtrer pour ne garder que les realms autorisés qui existent dans Keycloak
                availableRealms = new ArrayList<>();
                for (String authorizedRealm : authorizedRealms) {
                    if (allRealms.contains(authorizedRealm)) {
                        availableRealms.add(authorizedRealm);
                    }
                }
                LOGGER.info("Realms autorisés pour l'utilisateur: " + availableRealms.size());

                // Définir le premier realm autorisé comme realm par défaut
                if (!availableRealms.isEmpty() && !availableRealms.contains(realmName)) {
                    realmName = availableRealms.get(0);
                }
            }
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des realms depuis Keycloak: " + e.getMessage());
            LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e);
            // Fallback: liste vide plutôt que des données fictives
            availableRealms = Collections.emptyList();
        }
    }

    /**
     * Navigation vers le profil utilisateur
     */
    public String goToUserProfile() {
        return OUTCOME_USER_PROFILE;
    }

    /**
     * Navigation vers l'édition utilisateur
     */
    public String goToUserEdit() {
        return OUTCOME_USER_EDIT;
    }

    /**
     * Navigation vers la création utilisateur
     */
    public String goToUserCreate() {
        return OUTCOME_USER_CREATE;
    }

    // Méthodes utilitaires pour les messages
    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));
    }
}

