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.importexport.ImportResultDTO;
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.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.event.ActionEvent;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.ws.rs.core.Response;
import lombok.Data;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.primefaces.PrimeFaces;
import org.primefaces.model.FilterMeta;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortMeta;
import org.primefaces.model.file.UploadedFile;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.eclipse.microprofile.config.inject.ConfigProperty;

/**
 * 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;

    @ConfigProperty(name = "lions.user.manager.default.realm", defaultValue = "lions-user-manager")
    String defaultRealm;

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

    // Propriétés pour la recherche
    private UserSearchCriteriaDTO searchCriteria = UserSearchCriteriaDTO.builder().build();
    private String searchText;
    private String realmName;
    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;

    // KPIs chargés depuis le serveur (indépendants de la pagination/filtres)
    private long kpiTotalUsers = 0;
    private long activeUsersCount = 0;
    private long disabledUsersCount = 0;

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

    // Champs pour réinitialisation mot de passe
    private String newPassword;
    private String newPasswordConfirm;

    // Champ pour l'import CSV
    private UploadedFile importedFile;
    private ImportResultDTO lastImportResult;

    @PostConstruct
    public void init() {
        this.realmName = defaultRealm;
        LOGGER.info("Initialisation de UserListBean - realm: " + realmName);
        loadRealms();
        loadStats();

        users = new LazyDataModel<UserDTO>() {
            @Override
            public String getRowKey(UserDTO user) {
                return user.getId();
            }

            @Override
            public UserDTO getRowData(String rowKey) {
                List<UserDTO> list = (List<UserDTO>) getWrappedData();
                if (list != null) {
                    for (UserDTO user : list) {
                        if (user.getId().equals(rowKey)) {
                            return user;
                        }
                    }
                }
                return null;
            }

            @Override
            public int count(Map<String, FilterMeta> filterBy) {
                return (int) totalRecords;
            }

            @Override
            public List<UserDTO> load(int first, int pageSize, Map<String, SortMeta> sortBy,
                    Map<String, FilterMeta> filterBy) {
                try {
                    int page = first / pageSize;

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

                    UserSearchResultDTO result = userServiceClient.searchUsers(criteria);
                    List<UserDTO> data = result.getUsers() != null ? result.getUsers() : new ArrayList<>();

                    long total = result.getTotalCount() != null ? result.getTotalCount() : 0;
                    this.setRowCount((int) total);
                    totalRecords = total;

                    return data;
                } catch (Exception e) {
                    LOGGER.severe("Erreur loading: " + e.getMessage());
                    return new ArrayList<>();
                }
            }
        };
    }

    /**
     * Charger la liste des utilisateurs
     * (Deprecated: Utiliser LazyDataModel)
     */
    public void loadUsers() {
        // La méthode load du LazyDataModel est appelée automatiquement par le composant
    }

    /**
     * Rechercher des utilisateurs
     */
    public void search() {
        currentPage = 0;
        if (PrimeFaces.current().isAjaxRequest()) {
            PrimeFaces.current().executeScript("PF('userTableWidget').getPaginator().setPage(0);");
        }
    }

    /**
     * Réinitialiser la recherche
     */
    public void resetSearch() {
        searchText = null;
        selectedStatut = null;
        currentPage = 0;
        if (PrimeFaces.current().isAjaxRequest()) {
            PrimeFaces.current().executeScript("PF('userTableWidget').getPaginator().setPage(0);");
        }
    }

    /**
     * Réinitialiser le mot de passe
     */
    public void resetPassword(String userId) {
        if (newPassword != null && !newPassword.isEmpty() && newPassword.equals(newPasswordConfirm)) {
            try {
                // Utilisation du DTO pour la demande de réinitialisation
                dev.lions.user.manager.dto.user.PasswordResetRequestDTO request = new dev.lions.user.manager.dto.user.PasswordResetRequestDTO(
                        newPassword, false);
                userServiceClient.resetPassword(userId, realmName, request);
                addSuccessMessage("Mot de passe réinitialisé avec succès");
                // Clear fields
                newPassword = null;
                newPasswordConfirm = null;
            } catch (Exception e) {
                LOGGER.severe("Erreur lors de la réinitialisation du mot de passe: " + e.getMessage());
                addErrorMessage("Erreur lors de la réinitialisation: " + e.getMessage());
            }
        } else {
            addErrorMessage("Les mots de passe sont invalides ou ne correspondent pas");
        }
    }

    /**
     * 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 {
            userServiceClient.activateUser(userId, realmName);
            activeUsersCount++;
            disabledUsersCount = Math.max(0, disabledUsersCount - 1);
            addSuccessMessage("Utilisateur activé avec succès");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'activation: " + e.getMessage());
            addErrorMessage("Erreur lors de l'activation: " + e.getMessage());
        }
    }

    /**
     * Désactiver un utilisateur
     */
    public void deactivateUser(String userId) {
        try {
            userServiceClient.deactivateUser(userId, realmName, "Désactivé par l'administrateur");
            activeUsersCount = Math.max(0, activeUsersCount - 1);
            disabledUsersCount++;
            addSuccessMessage("Utilisateur désactivé avec succès");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la désactivation: " + e.getMessage());
            addErrorMessage("Erreur lors de la désactivation: " + e.getMessage());
        }
    }

    /**
     * Supprimer un utilisateur
     */
    public void deleteUser(String userId) {
        try {
            userServiceClient.deleteUser(userId, realmName, false);
            kpiTotalUsers = Math.max(0, kpiTotalUsers - 1);
            addSuccessMessage("Utilisateur supprimé avec succès");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la suppression: " + e.getMessage());
            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());
        }
    }

    /**
     * Pourcentage d'utilisateurs actifs
     */
    public int getActiveUsersPercentage() {
        if (kpiTotalUsers == 0) return 0;
        return (int) Math.round((double) activeUsersCount / kpiTotalUsers * 100);
    }

    /**
     * Pourcentage d'utilisateurs désactivés
     */
    public int getDisabledUsersPercentage() {
        if (kpiTotalUsers == 0) return 0;
        return (int) Math.round((double) disabledUsersCount / kpiTotalUsers * 100);
    }

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

    /**
     * Changement de realm (filtre + rechargement des KPIs)
     */
    public void onRealmChange() {
        currentPage = 0;
        loadStats();
        if (PrimeFaces.current().isAjaxRequest()) {
            PrimeFaces.current().executeScript("PF('userTableWidget').getPaginator().setPage(0);");
        }
    }

    /**
     * Charger les statistiques KPI depuis le serveur
     */
    private void loadStats() {
        try {
            UserSearchCriteriaDTO totalCriteria = UserSearchCriteriaDTO.builder()
                    .realmName(realmName).page(0).pageSize(1).build();
            UserSearchResultDTO totalResult = userServiceClient.searchUsers(totalCriteria);
            kpiTotalUsers = totalResult.getTotalCount() != null ? totalResult.getTotalCount() : 0;

            UserSearchCriteriaDTO activeCriteria = UserSearchCriteriaDTO.builder()
                    .realmName(realmName).enabled(true).page(0).pageSize(1).build();
            UserSearchResultDTO activeResult = userServiceClient.searchUsers(activeCriteria);
            activeUsersCount = activeResult.getTotalCount() != null ? activeResult.getTotalCount() : 0;

            disabledUsersCount = kpiTotalUsers - activeUsersCount;
        } catch (Exception e) {
            LOGGER.severe("Erreur chargement statistiques KPI: " + e.getMessage());
        }
    }

    /**
     * Exporter les utilisateurs vers un fichier CSV téléchargeable
     */
    public void exportToCSV() {
        try {
            Response response = userServiceClient.exportUsersToCSV(realmName);
            String csvContent = response.readEntity(String.class);

            FacesContext facesContext = FacesContext.getCurrentInstance();
            ExternalContext externalContext = facesContext.getExternalContext();
            externalContext.responseReset();
            externalContext.setResponseContentType("text/csv");
            externalContext.setResponseHeader("Content-Disposition",
                    "attachment; filename=\"utilisateurs-" + realmName + ".csv\"");
            externalContext.setResponseCharacterEncoding("UTF-8");

            OutputStream outputStream = externalContext.getResponseOutputStream();
            outputStream.write(csvContent.getBytes(StandardCharsets.UTF_8));
            outputStream.flush();

            facesContext.responseComplete();
        } catch (IOException e) {
            LOGGER.severe("Erreur I/O lors de l'export CSV: " + e.getMessage());
            addErrorMessage("Erreur lors de l'export CSV: " + e.getMessage());
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'export CSV: " + e.getMessage());
            addErrorMessage("Erreur lors de l'export CSV: " + e.getMessage());
        }
    }

    /**
     * Importer des utilisateurs depuis un fichier CSV
     */
    public void importUsers() {
        if (importedFile == null) {
            addErrorMessage("Veuillez sélectionner un fichier CSV à importer.");
            return;
        }
        try {
            String csvContent = new String(importedFile.getContent(), StandardCharsets.UTF_8);
            this.lastImportResult = userServiceClient.importUsersFromCSV(realmName, csvContent);

            if (lastImportResult != null) {
                String msg = lastImportResult.getSuccessCount() + " utilisateur(s) importé(s), "
                        + lastImportResult.getErrorCount() + " erreur(s).";
                if (lastImportResult.getErrorCount() == 0) {
                    addSuccessMessage(msg);
                } else {
                    addMessage(FacesMessage.SEVERITY_WARN, "Import partiel", msg);
                }
                loadStats();
            }
            importedFile = null;
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'import CSV: " + e.getMessage());
            addErrorMessage("Erreur lors de l'import: " + e.getMessage());
        }
    }

    private void addMessage(FacesMessage.Severity severity, String summary, String detail) {
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(severity, summary, detail));
    }

    /**
     * Charger les realms disponibles depuis Keycloak
     */
    private void loadRealms() {
        try {
            availableRealms = realmServiceClient.getAllRealms();
            LOGGER.info("Realms chargés: " + availableRealms);
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des realms: " + e.getMessage());
            // Fallback en cas d'erreur
            availableRealms = List.of("master", "lions-user-manager", "btpxpress", "unionflow");
        }
    }

    /**
     * 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));
    }
}
