package dev.lions.unionflow.client.view;

import dev.lions.unionflow.client.dto.MembreDTO;
import dev.lions.unionflow.client.service.MembreService;
import dev.lions.unionflow.client.service.AssociationService;
import dev.lions.unionflow.client.service.NotificationService;
import dev.lions.unionflow.client.service.CotisationService;
import dev.lions.unionflow.server.api.dto.membre.MembreSearchCriteria;
import dev.lions.unionflow.server.api.dto.organisation.OrganisationDTO;
import dev.lions.unionflow.client.dto.AssociationDTO;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import jakarta.inject.Inject;
import jakarta.annotation.PostConstruct;
import jakarta.faces.context.FacesContext;
import jakarta.faces.application.FacesMessage;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.IOException;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;

@Named("membreListeBean")
@ViewScoped
@Getter
@Setter
public class MembreListeBean implements Serializable {
    
    private static final long serialVersionUID = 1L;
    private static final Logger LOGGER = Logger.getLogger(MembreListeBean.class.getName());
    
    @Inject
    @RestClient
    MembreService membreService;
    
    @Inject
    @RestClient
    AssociationService associationService;
    
    @Inject
    @RestClient
    NotificationService notificationService;
    
    @Inject
    @RestClient
    CotisationService cotisationService;
    
    // Statistiques générales - Utilisation directe du DTO du service
    @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
    private MembreService.StatistiquesMembreDTO statistiques;
    
    // Filtres - Utilisation du DTO du serveur API (DRY/WOU)
    @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
    private MembreSearchCriteria searchCriteria = MembreSearchCriteria.builder().build();
    
    // Filtres additionnels non couverts par MembreSearchCriteria (spécifiques à l'UI)
    private String typeFilter = "";
    private String cotisationFilter = "";
    private Boolean desEnfants;
    
    // Messages groupés
    private String sujetMessage;
    private String contenuMessage;
    private List<String> canauxMessage = new ArrayList<>();
    
    // Contact membre
    private MembreDTO membreAContacter;
    private String messageContact;
    private String sujetContact;
    private boolean dialogContactVisible = false;
    
    // Import/Export
    private boolean mettreAJourExistants = false;
    private String formatExport = "EXCEL";
    private List<String> colonnesExport = new ArrayList<>();
    private boolean exporterSelection = false;
    
    // Données
    // Pas de getter Lombok car getter personnalisé retourne membresFiltres
    @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
    private List<MembreDTO> membres = new ArrayList<>();
    private List<MembreDTO> selectedMembres = new ArrayList<>();
    private List<MembreDTO> membresFiltres = new ArrayList<>();
    // Utilisation directe de OrganisationDTO du serveur API (DRY/WOU)
    private List<OrganisationDTO> organisationsDisponibles = new ArrayList<>();
    
    @PostConstruct
    public void init() {
        try {
            chargerMembres();
            chargerStatistiques();
            chargerOrganisations();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'initialisation: " + e.getMessage());
            // Initialiser les statistiques à null (sera géré par les getters)
            this.statistiques = null;
        }
    }
    
    private void chargerMembres() {
        try {
            // Récupération de tous les membres via le service REST
            membres = membreService.listerTous();
            membresFiltres = new ArrayList<>(membres);
            
            LOGGER.info("Chargement de " + membres.size() + " membres depuis le serveur");
            
        } catch (Exception e) {
            LOGGER.severe("Impossible de charger les membres depuis le serveur: " + e.getMessage());
            // Pas de données mockées - laisser la liste vide
            membres = new ArrayList<>();
            membresFiltres = new ArrayList<>();
        }
    }
    
    private void chargerStatistiques() {
        try {
            // Récupération directe du DTO de statistiques (DRY/WOU)
            this.statistiques = membreService.obtenirStatistiques();
            LOGGER.info("Statistiques chargées: " + (statistiques != null ? statistiques.getTotalMembres() : 0) + " membres");
        } catch (Exception e) {
            LOGGER.severe("Impossible de charger les statistiques: " + e.getMessage());
            this.statistiques = null;
        }
    }
    
    private void chargerOrganisations() {
        organisationsDisponibles = new ArrayList<>();
        try {
            // Utilisation directe de AssociationDTO (pas de OrganisationService disponible)
            List<AssociationDTO> associations = associationService.listerToutes(0, 1000);
            for (AssociationDTO assoc : associations) {
                // Conversion vers OrganisationDTO pour compatibilité avec MembreSearchCriteria
                OrganisationDTO org = new OrganisationDTO();
                org.setId(assoc.getId());
                org.setNom(assoc.getNom());
                organisationsDisponibles.add(org);
            }
            LOGGER.info("Chargement de " + organisationsDisponibles.size() + " organisations disponibles");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des organisations: " + e.getMessage());
        }
    }
    
    // Actions de recherche et filtrage
    public void rechercher() {
        try {
            // Utilisation de MembreSearchCriteria (DRY/WOU)
            searchCriteria.sanitize();
            // Si query est défini, l'utiliser pour nom (recherche générale)
            String nomRecherche = searchCriteria.getQuery() != null ? searchCriteria.getQuery() : searchCriteria.getNom();
            List<MembreDTO> resultats = membreService.rechercher(
                nomRecherche,  // nom (ou query si défini)
                searchCriteria.getPrenom(),  // prenom
                searchCriteria.getEmail(),  // email
                searchCriteria.getTelephone(),  // telephone
                searchCriteria.getStatut(),
                searchCriteria.getOrganisationIds() != null && !searchCriteria.getOrganisationIds().isEmpty() 
                    ? searchCriteria.getOrganisationIds().get(0) : null,  // associationId
                0,     // page
                100    // size
            );
            
            membresFiltres = resultats;
            LOGGER.info("Recherche effectuée: " + membresFiltres.size() + " résultats");
            
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la recherche: " + e.getMessage());
            membresFiltres = new ArrayList<>();
        }
    }
    
    public void reinitialiserFiltres() {
        // Réinitialisation du DTO de critères de recherche (DRY/WOU)
        searchCriteria = MembreSearchCriteria.builder().build();
        typeFilter = "";
        cotisationFilter = "";
        desEnfants = null;
        
        membresFiltres = new ArrayList<>(membres);
    }
    
    public void actualiser() {
        chargerMembres();
        chargerStatistiques();
        chargerOrganisations();
    }
    
    // Constantes de navigation outcomes (WOU/DRY - réutilisables)
    private static final String OUTCOME_MEMBRE_LISTE = "membreListPage";
    private static final String OUTCOME_MEMBRE_PROFIL = "membreProfilPage";
    private static final String OUTCOME_MEMBRE_MODIFIER = "membreModifierPage";
    private static final String OUTCOME_COTISATIONS = "cotisationCollectPage";
    
    public String modifierMembre(MembreDTO membre) {
        // Utilisation de navigation outcome au lieu de chemin direct (WOU/DRY)
        return OUTCOME_MEMBRE_MODIFIER + "?id=" + membre.getId() + "&faces-redirect=true";
    }
    
    // Propriétés pour la page de modification
    private UUID membreSelectionneId;
    private MembreDTO membreSelectionne;
    
    public void chargerMembreSelectionne() {
        if (membreSelectionneId != null) {
            try {
                membreSelectionne = membreService.obtenirParId(membreSelectionneId);
                LOGGER.info("Membre chargé pour modification: " + membreSelectionne.getNomComplet());
            } catch (Exception e) {
                LOGGER.severe("Erreur lors du chargement du membre: " + e.getMessage());
                FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", 
                        "Impossible de charger le membre: " + e.getMessage()));
            }
        }
    }
    
    public String modifierMembreSelectionne() {
        try {
            membreService.modifier(membreSelectionne.getId(), membreSelectionne);
            LOGGER.info("Membre modifié: " + membreSelectionne.getNomComplet());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", 
                    "Le membre a été modifié avec succès"));
            return OUTCOME_MEMBRE_LISTE + "?faces-redirect=true";
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la modification: " + e.getMessage());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", 
                    "Impossible de modifier le membre: " + e.getMessage()));
            return null;
        }
    }
    
    // Méthode pour obtenir la liste des organisations pour le dropdown (WOU/DRY)
    public List<jakarta.faces.model.SelectItem> getOrganisationsSelectItems() {
        List<jakarta.faces.model.SelectItem> items = new ArrayList<>();
        items.add(new jakarta.faces.model.SelectItem("", "Toutes entités"));
        for (OrganisationDTO org : organisationsDisponibles) {
            items.add(new jakarta.faces.model.SelectItem(org.getId().toString(), org.getNom()));
        }
        return items;
    }
    
    public String gererCotisations(MembreDTO membre) {
        // Utilisation de navigation outcome au lieu de chemin direct (WOU/DRY)
        return OUTCOME_COTISATIONS + "?membreId=" + membre.getId() + "&faces-redirect=true";
    }
    
    public void appliquerFiltresAvances() {
        // Appliquer les filtres avancés en utilisant MembreSearchCriteria (DRY/WOU)
        searchCriteria.sanitize();
        rechercher();
        LOGGER.info("Application des filtres avancés: " + searchCriteria.getDescription());
    }
    
    // Méthodes de complétion pour les autocomplétions (WOU/DRY - réutilisables)
    public List<String> completerVilles(String query) {
        try {
            // Utilisation du service REST pour obtenir les villes distinctes (WOU/DRY)
            return membreService.obtenirVilles(query);
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la récupération des villes: " + e.getMessage());
            return new ArrayList<>();
        }
    }
    
    public List<String> completerProfessions(String query) {
        try {
            // Utilisation du service REST pour obtenir les professions distinctes (WOU/DRY)
            return membreService.obtenirProfessions(query);
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la récupération des professions: " + e.getMessage());
            return new ArrayList<>();
        }
    }
    
    // Actions supplémentaires pour les membres
    public void suspendreMembre(MembreDTO membre) {
        try {
            membreService.suspendre(membre.getId());
            membre.setStatut("SUSPENDU");
            LOGGER.info("Membre suspendu: " + membre.getNomComplet());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", 
                    "Le membre a été suspendu avec succès"));
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la suspension: " + e.getMessage());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", 
                    "Impossible de suspendre le membre: " + e.getMessage()));
        }
    }
    
    public void reactiverMembre(MembreDTO membre) {
        try {
            membreService.activer(membre.getId());
            membre.setStatut("ACTIF");
            LOGGER.info("Membre réactivé: " + membre.getNomComplet());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", 
                    "Le membre a été réactivé avec succès"));
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la réactivation: " + e.getMessage());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", 
                    "Impossible de réactiver le membre: " + e.getMessage()));
        }
    }
    
    public void contacterMembre(MembreDTO membre) {
        this.membreAContacter = membre;
        this.sujetContact = "";
        this.messageContact = "";
        this.dialogContactVisible = true;
        LOGGER.info("Ouverture du dialogue de contact pour: " + membre.getNomComplet());
    }
    
    public void envoyerMessageContact() {
        if (membreAContacter == null || messageContact == null || messageContact.trim().isEmpty()) {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", 
                    "Veuillez saisir un message"));
            return;
        }
        
        try {
            String sujet = sujetContact != null && !sujetContact.trim().isEmpty() 
                ? sujetContact 
                : "Message depuis UnionFlow";
            
            // Envoyer la notification via le service
            List<UUID> membreIds = List.of(membreAContacter.getId());
            List<String> canaux = List.of("IN_APP", "EMAIL");
            
            NotificationService.NotificationGroupeeRequest request = 
                new NotificationService.NotificationGroupeeRequest(membreIds, sujet, messageContact, canaux);
            
            notificationService.envoyerNotificationsGroupees(request);
            
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", 
                    "Message envoyé à " + membreAContacter.getNomComplet()));
            
            // Fermer le dialog
            this.dialogContactVisible = false;
            this.membreAContacter = null;
            this.sujetContact = "";
            this.messageContact = "";
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'envoi du message: " + e.getMessage());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", 
                    "Impossible d'envoyer le message: " + e.getMessage()));
        }
    }
    
    public void annulerContact() {
        this.dialogContactVisible = false;
        this.membreAContacter = null;
        this.sujetContact = "";
        this.messageContact = "";
    }
    
    public void rappelCotisationsGroupe() {
        if (selectedMembres == null || selectedMembres.isEmpty()) {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", 
                    "Veuillez sélectionner au moins un membre"));
            return;
        }
        
        try {
            LOGGER.info("Envoi de rappels de cotisations à " + selectedMembres.size() + " membres");
            List<UUID> membreIds = selectedMembres.stream()
                .map(MembreDTO::getId)
                .collect(java.util.stream.Collectors.toList());
            
            Map<String, Integer> result = cotisationService.envoyerRappelsGroupes(membreIds);
            int rappelsEnvoyes = result != null && result.containsKey("rappelsEnvoyes") 
                ? result.get("rappelsEnvoyes") : membreIds.size();
            
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", 
                    "Rappels de cotisations envoyés à " + rappelsEnvoyes + " membres"));
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'envoi des rappels: " + e.getMessage());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", 
                    "Impossible d'envoyer les rappels: " + e.getMessage()));
        }
    }
    
    public void exporterSelection() {
        if (selectedMembres == null || selectedMembres.isEmpty()) {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", 
                    "Veuillez sélectionner au moins un membre"));
            return;
        }
        
        try {
            LOGGER.info("Export de la sélection: " + selectedMembres.size() + " membres");
            List<UUID> membreIds = selectedMembres.stream()
                .map(MembreDTO::getId)
                .collect(java.util.stream.Collectors.toList());
            
            byte[] excelData = membreService.exporterSelection(membreIds, formatExport);
            
            // Téléchargement du fichier Excel via JSF (WOU/DRY - réutilise la logique d'export)
            FacesContext facesContext = FacesContext.getCurrentInstance();
            HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
            
            response.reset();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename=\"membres_selection_" + 
                LocalDate.now() + "." + (formatExport != null ? formatExport.toLowerCase() : "xlsx") + "\"");
            response.setContentLength(excelData.length);
            
            response.getOutputStream().write(excelData);
            response.getOutputStream().flush();
            facesContext.responseComplete();
            
            LOGGER.info("Export Excel généré et téléchargé: " + excelData.length + " bytes");
        } catch (IOException e) {
            LOGGER.severe("Erreur lors du téléchargement de l'export: " + e.getMessage());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", 
                    "Impossible de télécharger l'export: " + e.getMessage()));
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'export: " + e.getMessage());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", 
                    "Impossible d'exporter la sélection: " + e.getMessage()));
        }
    }
    
    public void envoyerMessageGroupe() {
        if (selectedMembres == null || selectedMembres.isEmpty()) {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", 
                    "Veuillez sélectionner au moins un membre"));
            return;
        }
        
        if (sujetMessage == null || sujetMessage.trim().isEmpty()) {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", 
                    "Le sujet du message est obligatoire"));
            return;
        }
        
        if (contenuMessage == null || contenuMessage.trim().isEmpty()) {
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", 
                    "Le contenu du message est obligatoire"));
            return;
        }
        
        try {
            LOGGER.info("Envoi de message groupé à " + selectedMembres.size() + " membres");
            List<UUID> membreIds = selectedMembres.stream()
                .map(MembreDTO::getId)
                .collect(java.util.stream.Collectors.toList());
            
            NotificationService.NotificationGroupeeRequest request = 
                new NotificationService.NotificationGroupeeRequest(
                    membreIds, 
                    sujetMessage, 
                    contenuMessage, 
                    canauxMessage != null ? canauxMessage : new ArrayList<>()
                );
            
            Map<String, Integer> result = notificationService.envoyerNotificationsGroupees(request);
            int notificationsCreees = result != null && result.containsKey("notificationsCreees") 
                ? result.get("notificationsCreees") : membreIds.size();
            
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", 
                    "Message envoyé à " + notificationsCreees + " membres"));
            // Réinitialiser les champs
            sujetMessage = null;
            contenuMessage = null;
            canauxMessage = new ArrayList<>();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'envoi du message: " + e.getMessage());
            FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", 
                    "Impossible d'envoyer le message: " + e.getMessage()));
        }
    }
    
    // Import/Export
    public void importerMembres() {
        // Logique d'import des membres
        LOGGER.info("Import des membres");
    }
    
    public void telechargerModele() {
        // Télécharger modèle d'import
        LOGGER.info("Téléchargement du modèle");
    }
    
    // Actions avec DTOs
    public String voirProfil(MembreDTO membre) {
        // Utilisation de navigation outcome au lieu de chemin direct (WOU/DRY)
        return OUTCOME_MEMBRE_PROFIL + "?id=" + membre.getId() + "&faces-redirect=true";
    }
    
    public void activerMembre(MembreDTO membre) {
        try {
            membreService.activer(membre.getId());
            membre.setStatut("ACTIF");
            LOGGER.info("Membre activé: " + membre.getNomComplet());
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'activation: " + e.getMessage());
        }
    }
    
    public void desactiverMembre(MembreDTO membre) {
        try {
            membreService.desactiver(membre.getId());
            membre.setStatut("INACTIF");
            LOGGER.info("Membre désactivé: " + membre.getNomComplet());
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la désactivation: " + e.getMessage());
        }
    }
    
    public void exporterMembres() {
        try {
            byte[] excelData = membreService.exporterExcel(formatExport, null, 
                searchCriteria.getStatut() != null && !searchCriteria.getStatut().isEmpty() 
                    ? searchCriteria.getStatut() : null);
            
            // Téléchargement du fichier Excel via JSF
            FacesContext facesContext = FacesContext.getCurrentInstance();
            HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
            
            response.reset();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename=\"membres_export_" + 
                LocalDate.now() + "." + (formatExport != null ? formatExport.toLowerCase() : "xlsx") + "\"");
            response.setContentLength(excelData.length);
            
            response.getOutputStream().write(excelData);
            response.getOutputStream().flush();
            facesContext.responseComplete();
            
            LOGGER.info("Export Excel généré et téléchargé: " + excelData.length + " bytes");
        } catch (IOException e) {
            LOGGER.severe("Erreur lors du téléchargement de l'export: " + e.getMessage());
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'export: " + e.getMessage());
        }
    }
    
    // Getters et Setters pour les statistiques (compatibilité avec les pages XHTML)
    public int getTotalMembres() { 
        return statistiques != null && statistiques.getTotalMembres() != null 
            ? statistiques.getTotalMembres().intValue() : 0; 
    }
    
    public int getMembresActifs() { 
        return statistiques != null && statistiques.getMembresActifs() != null 
            ? statistiques.getMembresActifs().intValue() : 0; 
    }
    
    public int getCotisationsAJour() { 
        // Calcul approximatif (à implémenter côté serveur)
        return (int) (getMembresActifs() * 0.85); 
    }
    
    public int getNouveauxMembres() { 
        return statistiques != null && statistiques.getNouveauxMembres30Jours() != null 
            ? statistiques.getNouveauxMembres30Jours().intValue() : 0; 
    }
    
    public int getMembresInactifs() { 
        return statistiques != null && statistiques.getMembresInactifs() != null 
            ? statistiques.getMembresInactifs().intValue() : 0; 
    }
    
    // Getters et Setters de compatibilité pour les filtres (délégation à MembreSearchCriteria)
    public String getSearchFilter() { 
        return searchCriteria.getQuery() != null ? searchCriteria.getQuery() : ""; 
    }
    public void setSearchFilter(String searchFilter) { 
        searchCriteria.setQuery(searchFilter != null && !searchFilter.isEmpty() ? searchFilter : null);
    }
    
    public String getStatutFilter() { 
        return searchCriteria.getStatut() != null ? searchCriteria.getStatut() : ""; 
    }
    public void setStatutFilter(String statutFilter) { 
        searchCriteria.setStatut(statutFilter != null && !statutFilter.isEmpty() ? statutFilter : null);
    }
    
    // typeFilter et cotisationFilter sont gérés par Lombok @Getter @Setter
    
    public String getEntiteFilter() { 
        // Retourne le premier ID d'organisation si présent
        if (searchCriteria.getOrganisationIds() != null && !searchCriteria.getOrganisationIds().isEmpty()) {
            return searchCriteria.getOrganisationIds().get(0).toString();
        }
        return "";
    }
    public void setEntiteFilter(String entiteFilter) { 
        if (entiteFilter != null && !entiteFilter.isEmpty()) {
            try {
                UUID orgId = UUID.fromString(entiteFilter);
                searchCriteria.setOrganisationIds(List.of(orgId));
            } catch (IllegalArgumentException e) {
                LOGGER.warning("ID d'organisation invalide: " + entiteFilter);
            }
        } else {
            searchCriteria.setOrganisationIds(null);
        }
    }
    
    public Integer getAgeMin() { return searchCriteria.getAgeMin(); }
    public void setAgeMin(Integer ageMin) { searchCriteria.setAgeMin(ageMin); }
    
    public Integer getAgeMax() { return searchCriteria.getAgeMax(); }
    public void setAgeMax(Integer ageMax) { searchCriteria.setAgeMax(ageMax); }
    
    public String getGenreFilter() { 
        // MembreSearchCriteria n'a pas de champ genre, on pourrait utiliser un champ personnalisé
        // Pour l'instant, on retourne vide
        return "";
    }
    public void setGenreFilter(String genreFilter) { 
        // À implémenter si nécessaire dans MembreSearchCriteria
    }
    
    public String getVilleFilter() { return searchCriteria.getVille() != null ? searchCriteria.getVille() : ""; }
    public void setVilleFilter(String villeFilter) { 
        searchCriteria.setVille(villeFilter != null && !villeFilter.isEmpty() ? villeFilter : null);
    }
    
    public LocalDate getDateAdhesionDebut() { return searchCriteria.getDateAdhesionMin(); }
    public void setDateAdhesionDebut(LocalDate dateAdhesionDebut) { searchCriteria.setDateAdhesionMin(dateAdhesionDebut); }
    
    public LocalDate getDateAdhesionFin() { return searchCriteria.getDateAdhesionMax(); }
    public void setDateAdhesionFin(LocalDate dateAdhesionFin) { searchCriteria.setDateAdhesionMax(dateAdhesionFin); }
    
    public String getProfessionFilter() { return searchCriteria.getProfession() != null ? searchCriteria.getProfession() : ""; }
    public void setProfessionFilter(String professionFilter) { 
        searchCriteria.setProfession(professionFilter != null && !professionFilter.isEmpty() ? professionFilter : null);
    }
    
    // desEnfants, sujetMessage, contenuMessage, canauxMessage, mettreAJourExistants, 
    // formatExport, colonnesExport, exporterSelection, selectedMembres, membresFiltres, 
    // organisationsDisponibles sont gérés par Lombok @Getter @Setter
    
    // Getter pour MembreSearchCriteria (pour utilisation avancée)
    public MembreSearchCriteria getSearchCriteria() { return searchCriteria; }
    public void setSearchCriteria(MembreSearchCriteria searchCriteria) { this.searchCriteria = searchCriteria; }
    
    // Getter spécial pour membres (retourne membresFiltres pour compatibilité)
    public List<MembreDTO> getMembres() { return membresFiltres; }
    public void setMembres(List<MembreDTO> membres) { this.membres = membres; }
    
    // Getter de compatibilité pour les pages XHTML utilisant "entitesDisponibles"
    // Note: liste.xhtml devrait utiliser organisationsDisponibles directement (WOU/DRY)
    @Deprecated
    public List<Entite> getEntitesDisponibles() { 
        // Conversion de OrganisationDTO vers Entite pour compatibilité
        List<Entite> entites = new ArrayList<>();
        for (OrganisationDTO org : organisationsDisponibles) {
            Entite entite = new Entite();
            entite.setId(org.getId());
            entite.setNom(org.getNom());
            entites.add(entite);
        }
        return entites;
    }
    
    // Classe interne de compatibilité (à supprimer après mise à jour de liste.xhtml)
    @Deprecated
    public static class Entite implements Serializable {
        private UUID id;
        private String nom;
        
        // Getters et setters explicites (Lombok peut avoir des problèmes avec les classes internes)
        public UUID getId() { return id; }
        public void setId(UUID id) { this.id = id; }
        public String getNom() { return nom; }
        public void setNom(String nom) { this.nom = nom; }
    }
}