package dev.lions.unionflow.client.view;

import dev.lions.unionflow.server.api.dto.cotisation.response.CotisationResponse;
import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse;
import dev.lions.unionflow.client.service.CotisationService;
import dev.lions.unionflow.client.service.ErrorHandlerService;
import dev.lions.unionflow.client.service.ExportClientService;
import dev.lions.unionflow.client.service.MembreService;
import dev.lions.unionflow.client.service.RetryService;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.logging.Logger;
import java.io.OutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * Bean pour la gestion des cotisations d'un membre (WOU/DRY)
 * 
 * @author UnionFlow Team
 * @version 2.0
 */
@Named("membreCotisationBean")
@ViewScoped
public class MembreCotisationBean implements Serializable {
    
    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(MembreCotisationBean.class);
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");
    
    // Constantes de navigation outcomes (WOU/DRY - réutilisables)
    private static final String OUTCOME_MEMBRE_HISTORIQUE_COTISATIONS = "membreHistoriqueCotisationsPage";
    private static final String OUTCOME_MEMBRE_PROFIL = "membreProfilPage";
    
    @Inject
    @RestClient
    private MembreService membreService;

    @Inject
    @RestClient
    private CotisationService cotisationService;

    @Inject
    @RestClient
    private ExportClientService exportService;

    @Inject
    ErrorHandlerService errorHandler;

    @Inject
    RetryService retryService;

    @Inject
    io.quarkus.security.identity.SecurityIdentity securityIdentity;
    
    // ID du membre (depuis viewParam)
    private UUID membreId;
    
    // Données du membre
    private MembreResponse membre;
    
    // Propriétés de base
    private String numeroMembre;
    private String statutCotisations;
    private String derniereMAJ;
    private boolean peutPayer;
    
    // Statistiques
    private int cotisationsPayees;
    private int cotisationsEnAttente;
    private BigDecimal montantDu;
    private BigDecimal totalVerse;
    private int progressionAnnuelle;
    
    // Filtres
    private String anneeFilter = "2024";
    private String statutFilter = "";
    private String typeFilter = "";
    
    // Paiement
    private Object cotisationSelectionnee;
    private String modePaiementChoisi = "WAVE";
    private String numeroWave;
    private String commentairePaiement;
    private BigDecimal montantAPayer = BigDecimal.ZERO;
    private String banqueAssociation = "Banque Atlantique";
    private String ibanAssociation = "SN12 1234 5678 9012 3456 7890 12";
    
    // Prélèvement automatique
    private String numeroWaveAuto;
    private int jourPrelevement = 5;
    private boolean notificationSMS = true;
    private String cotisationMensuelle = "5,000 FCFA";
    
    // Listes
    private List<Cotisation> cotisations = new ArrayList<>();
    private List<Echeance> prochainesEcheances = new ArrayList<>();
    private List<Cotisation> cotisationsImpayees = new ArrayList<>();
    
    // Totaux périodes
    private BigDecimal totalPayePeriode = BigDecimal.ZERO;
    private BigDecimal totalEnAttentePeriode = BigDecimal.ZERO;
    private BigDecimal totalEnRetardPeriode = BigDecimal.ZERO;
    private int tauxConformite = 85;
    
    // État
    private String statutMembre = "Actif";
    private String typeMembre = "Membre Actif";
    private String statutSeverity = "success";
    private int scorePonctualite = 85;
    private String commentairePonctualite = "Excellent membre, toujours à jour";
    
    @PostConstruct
    public void init() {
        // Si membreId est null, essayer de le récupérer depuis les paramètres de requête
        if (membreId == null) {
            String idParam = jakarta.faces.context.FacesContext.getCurrentInstance()
                .getExternalContext()
                .getRequestParameterMap()
                .get("id");
            if (idParam != null && !idParam.isEmpty()) {
                try {
                    membreId = UUID.fromString(idParam);
                } catch (IllegalArgumentException e) {
                    LOG.errorf(e, "ID de membre invalide: %s", idParam);
                    errorHandler.showWarning("Erreur", "ID de membre invalide");
                    return;
                }
            }
        }

        // Si toujours null, auto-détecter le membre connecté (Pattern DRY depuis DashboardMembreBean)
        if (membreId == null) {
            try {
                String username = securityIdentity.getPrincipal().getName();
                LOG.infof("Auto-détection du membre connecté: %s", username);

                // Récupérer directement le membre connecté via l'endpoint /me
                MembreResponse membreConnecte = retryService.executeWithRetrySupplier(
                    () -> membreService.obtenirMembreConnecte(),
                    "récupération du membre connecté"
                );

                if (membreConnecte != null) {
                    membreId = membreConnecte.getId();
                    numeroMembre = membreConnecte.getNumeroMembre();
                    LOG.infof("Membre connecté détecté: %s (%s)", numeroMembre, membreId);
                } else {
                    LOG.warnf("Aucun membre trouvé pour l'utilisateur: %s", username);
                    errorHandler.showWarning("Attention",
                        "Impossible de charger vos cotisations. Veuillez contacter l'administrateur.");
                    initialiserDonneesVides();
                    return;
                }
            } catch (Exception e) {
                LOG.errorf(e, "Erreur lors de l'auto-détection du membre connecté");
                errorHandler.handleException(e, "lors du chargement de vos cotisations", null);
                initialiserDonneesVides();
                return;
            }
        }

        if (membreId != null) {
            chargerMembre();
            chargerCotisations();
            calculerStatistiques();
        } else {
            initialiserDonneesVides();
        }
    }
    
    private void chargerMembre() {
        try {
            membre = retryService.executeWithRetrySupplier(
                () -> membreService.obtenirParId(membreId),
                "chargement d'un membre pour cotisations"
            );
            if (membre != null) {
                numeroMembre = membre.getNumeroMembre();
                statutCotisations = membre.getStatutCompte() != null ? membre.getStatutCompte() : "ACTIF";
                derniereMAJ = LocalDate.now().format(DATE_FORMATTER);
            }
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du chargement du membre");
            errorHandler.handleException(e, "lors du chargement du membre", null);
            initialiserDonneesVides();
        }
    }
    
    private void chargerCotisations() {
        try {
            // Utiliser la recherche avec filtres si nécessaire
            List<CotisationResponse> cotisationsDTO;
            
            if (statutFilter != null && !statutFilter.trim().isEmpty()) {
                // Filtrer par statut si spécifié
                cotisationsDTO = retryService.executeWithRetrySupplier(
                    () -> cotisationService.rechercher(
                        membreId, 
                        statutFilter, 
                        typeFilter != null && !typeFilter.trim().isEmpty() ? typeFilter : null,
                        anneeFilter != null && !anneeFilter.trim().isEmpty() ? Integer.parseInt(anneeFilter) : null,
                        null, // mois
                        0, 
                        100
                    ),
                    "recherche de cotisations avec filtres"
                );
            } else {
                // Sinon, obtenir toutes les cotisations du membre
                cotisationsDTO = retryService.executeWithRetrySupplier(
                    () -> cotisationService.obtenirParMembre(membreId, 0, 100),
                    "chargement des cotisations d'un membre"
                );
            }
            
            cotisations = new ArrayList<>();
            cotisationsImpayees = new ArrayList<>();
            
            for (CotisationResponse dto : cotisationsDTO) {
                // Filtrer par année si spécifié
                if (anneeFilter != null && !anneeFilter.trim().isEmpty()) {
                    int anneeFiltre = Integer.parseInt(anneeFilter);
                    if (dto.getDateEcheance() != null && dto.getDateEcheance().getYear() != anneeFiltre) {
                        continue;
                    }
                }
                
                Cotisation cotisation = convertirEnCotisation(dto);
                cotisations.add(cotisation);
                
                if (!"PAYEE".equals(cotisation.getStatut()) && !"PAYE".equals(cotisation.getStatut())) {
                    cotisationsImpayees.add(cotisation);
                }
            }
            
            LOG.infof("Cotisations chargées: %d pour le membre %s", cotisations.size(), membreId);
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du chargement des cotisations");
            errorHandler.handleException(e, "lors du chargement des cotisations", null);
            cotisations = new ArrayList<>();
            cotisationsImpayees = new ArrayList<>();
        }
    }
    
    private Cotisation convertirEnCotisation(CotisationResponse dto) {
        Cotisation cotisation = new Cotisation();
        cotisation.setReference(dto.getNumeroReference() != null ? dto.getNumeroReference() : "");
        cotisation.setLibelle(dto.getLibelle() != null ? dto.getLibelle() : "Cotisation");
        
        // Formater la période depuis la date d'échéance
        if (dto.getDateEcheance() != null) {
            String[] moisNoms = {"Janvier", "Février", "Mars", "Avril", "Mai", "Juin",
                                 "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"};
            int mois = dto.getDateEcheance().getMonthValue();
            int annee = dto.getDateEcheance().getYear();
            cotisation.setPeriode(moisNoms[mois - 1] + " " + annee);
        } else {
            cotisation.setPeriode("");
        }
        
        cotisation.setType(dto.getTypeCotisation() != null ? dto.getTypeCotisation() : "MENSUELLE");
        cotisation.setMontant(dto.getMontantDu() != null ? dto.getMontantDu() : BigDecimal.ZERO);
        cotisation.setStatut(dto.getStatut() != null ? dto.getStatut() : "EN_ATTENTE");
        cotisation.setDateEcheance(dto.getDateEcheance());
        
        // Convertir LocalDateTime en LocalDate pour datePaiement
        if (dto.getDatePaiement() != null) {
            cotisation.setDatePaiement(dto.getDatePaiement().toLocalDate());
        }

        // Note: CotisationResponse n'a pas de champ methodePaiement
        cotisation.setModePaiement(null);
        return cotisation;
    }
    
    private void calculerStatistiques() {
        cotisationsPayees = (int) cotisations.stream()
            .filter(c -> "PAYEE".equals(c.getStatut()) || "PAYE".equals(c.getStatut()))
            .count();
        cotisationsEnAttente = (int) cotisations.stream()
            .filter(c -> "EN_ATTENTE".equals(c.getStatut()))
            .count();
        montantDu = cotisations.stream()
            .filter(c -> !"PAYEE".equals(c.getStatut()) && !"PAYE".equals(c.getStatut()))
            .map(Cotisation::getMontant)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        totalVerse = cotisations.stream()
            .filter(c -> "PAYEE".equals(c.getStatut()) || "PAYE".equals(c.getStatut()))
            .map(Cotisation::getMontant)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        
        // Calculer la progression annuelle (basée sur le nombre de cotisations payées)
        int totalCotisationsAnnee = (int) cotisations.stream()
            .filter(c -> c.getDateEcheance() != null && c.getDateEcheance().getYear() == LocalDate.now().getYear())
            .count();
        progressionAnnuelle = totalCotisationsAnnee > 0 
            ? (cotisationsPayees * 100) / totalCotisationsAnnee 
            : 0;
        
        peutPayer = !cotisationsImpayees.isEmpty();
    }
    
    private void initialiserDonneesVides() {
        numeroMembre = "";
        statutCotisations = "Non renseigné";
        derniereMAJ = "";
        peutPayer = false;
        cotisationsPayees = 0;
        cotisationsEnAttente = 0;
        montantDu = BigDecimal.ZERO;
        totalVerse = BigDecimal.ZERO;
        progressionAnnuelle = 0;
        cotisations = new ArrayList<>();
        cotisationsImpayees = new ArrayList<>();
    }
    
    
    // Actions
    public String voirHistoriqueComplet() {
        // Utilisation de navigation outcome au lieu de chemin direct (WOU/DRY)
        return OUTCOME_MEMBRE_HISTORIQUE_COTISATIONS + "?faces-redirect=true";
    }
    
    public void telechargerRecus() {
        // Logique de téléchargement des reçus
    }
    
    public void payerCotisation(Object cotisation) {
        if (cotisation == null) {
            errorHandler.showWarning("Attention", "Aucune cotisation sélectionnée");
            return;
        }
        
        if (!(cotisation instanceof Cotisation)) {
            LOG.warnf("Type de cotisation invalide: %s", cotisation.getClass().getName());
            errorHandler.showWarning("Erreur", "Type de cotisation invalide");
            return;
        }
        
        Cotisation cot = (Cotisation) cotisation;
        cotisationSelectionnee = cot;
        
        // Rediriger vers la page de paiement avec l'ID de la cotisation
        // Note: Cette fonctionnalité nécessite une page de paiement dédiée
        LOG.infof("Redirection vers le paiement de la cotisation: %s", cot.getReference());
        errorHandler.showInfo("Information", "Redirection vers la page de paiement...");
    }
    
    public void actualiser() {
        // Actualiser les données depuis le backend (WOU/DRY)
        if (membreId == null) {
            errorHandler.showWarning("Attention", "Aucun membre sélectionné");
            return;
        }
        
        try {
            chargerMembre();
            chargerCotisations();
            calculerStatistiques();
            errorHandler.showSuccess("Actualisation", "Les données ont été actualisées");
            LOG.infof("Données actualisées pour le membre: %s", membreId);
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de l'actualisation");
            errorHandler.handleException(e, "lors de l'actualisation des données", null);
        }
    }
    
    /**
     * Applique les filtres et recharge les cotisations
     */
    public void appliquerFiltres() {
        chargerCotisations();
        calculerStatistiques();
    }
    
    public String confirmerPaiement() {
        // Logique de confirmation de paiement
        return null;
    }
    
    public void paiementWave() {
        // Logique de paiement Wave Money
    }
    
    public void genererAttestation() {
        // Logique de génération d'attestation
    }
    
    public void demanderRecu() {
        // Logique de demande de reçu
    }
    
    public void activerPrelevementAuto() {
        // Logique d'activation du prélèvement automatique
    }
    
    public void telechargerRecu(Object cotisation) {
        if (cotisation == null) {
            errorHandler.showWarning("Attention", "Aucune cotisation sélectionnée");
            return;
        }
        
        if (!(cotisation instanceof Cotisation)) {
            LOG.warnf("Type de cotisation invalide: %s", cotisation.getClass().getName());
            errorHandler.showWarning("Erreur", "Type de cotisation invalide");
            return;
        }
        
        Cotisation cot = (Cotisation) cotisation;
        
        // Vérifier que la cotisation est payée
        if (!"PAYEE".equals(cot.getStatut()) && !"PAYE".equals(cot.getStatut())) {
            errorHandler.showWarning("Attention", 
                "Cette cotisation n'est pas encore payée. Impossible de télécharger le reçu.");
            return;
        }
        
        if (cot.getId() == null) {
            errorHandler.showWarning("Attention", "Impossible de générer le reçu: cotisation sans identifiant");
            return;
        }
        try {
            byte[] recu = retryService.executeWithRetrySupplier(
                () -> exportService.genererRecu(cot.getId()),
                "génération d'un reçu"
            );
            String nomFichier = "recu-" + (cot.getReference() != null ? cot.getReference() : cot.getId()) + ".txt";
            telechargerFichier(recu, nomFichier, "text/plain");
            errorHandler.showSuccess("Reçu", "Reçu téléchargé pour " + cot.getReference());
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du téléchargement du reçu");
            errorHandler.handleException(e, "lors du téléchargement du reçu", null);
        }
    }
    
    private void telechargerFichier(byte[] data, String nomFichier, String contentType) {
        try {
            jakarta.faces.context.FacesContext fc = jakarta.faces.context.FacesContext.getCurrentInstance();
            ExternalContext ec = fc.getExternalContext();
            ec.responseReset();
            ec.setResponseContentType(contentType + "; charset=UTF-8");
            ec.setResponseContentLength(data.length);
            ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + nomFichier + "\"");
            OutputStream output = ec.getResponseOutputStream();
            output.write(data);
            output.flush();
            fc.responseComplete();
        } catch (Exception e) {
            LOG.errorf(e, "Erreur téléchargement fichier");
            throw new RuntimeException("Erreur lors du téléchargement", e);
        }
    }
    
    public void voirDetails(Object cotisation) {
        // Logique d'affichage des détails
    }
    
    // Getters et Setters
    public UUID getMembreId() { return membreId; }
    public void setMembreId(UUID membreId) { this.membreId = membreId; }
    
    public MembreResponse getMembre() { return membre; }
    public void setMembre(MembreResponse membre) { this.membre = membre; }
    
    public String getNumeroMembre() { return numeroMembre; }
    public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; }
    
    public String getStatutCotisations() { return statutCotisations; }
    public void setStatutCotisations(String statutCotisations) { this.statutCotisations = statutCotisations; }
    
    public String getDerniereMAJ() { return derniereMAJ; }
    public void setDerniereMAJ(String derniereMAJ) { this.derniereMAJ = derniereMAJ; }
    
    public boolean isPeutPayer() { return peutPayer; }
    public void setPeutPayer(boolean peutPayer) { this.peutPayer = peutPayer; }
    
    public int getCotisationsPayees() { return cotisationsPayees; }
    public void setCotisationsPayees(int cotisationsPayees) { this.cotisationsPayees = cotisationsPayees; }
    
    public int getCotisationsEnAttente() { return cotisationsEnAttente; }
    public void setCotisationsEnAttente(int cotisationsEnAttente) { this.cotisationsEnAttente = cotisationsEnAttente; }
    
    public BigDecimal getMontantDu() { return montantDu; }
    public void setMontantDu(BigDecimal montantDu) { this.montantDu = montantDu; }
    
    public BigDecimal getTotalVerse() { return totalVerse; }
    public void setTotalVerse(BigDecimal totalVerse) { this.totalVerse = totalVerse; }
    
    public int getProgressionAnnuelle() { return progressionAnnuelle; }
    public void setProgressionAnnuelle(int progressionAnnuelle) { this.progressionAnnuelle = progressionAnnuelle; }
    
    public String getAnneeFilter() { return anneeFilter; }
    public void setAnneeFilter(String anneeFilter) { this.anneeFilter = anneeFilter; }
    
    public String getStatutFilter() { return statutFilter; }
    public void setStatutFilter(String statutFilter) { this.statutFilter = statutFilter; }
    
    public String getTypeFilter() { return typeFilter; }
    public void setTypeFilter(String typeFilter) { this.typeFilter = typeFilter; }
    
    public List<Cotisation> getCotisations() { return cotisations; }
    public void setCotisations(List<Cotisation> cotisations) { this.cotisations = cotisations; }
    
    public List<Echeance> getProchainesEcheances() { return prochainesEcheances; }
    public void setProchainesEcheances(List<Echeance> prochainesEcheances) { this.prochainesEcheances = prochainesEcheances; }
    
    public Object getCotisationSelectionnee() { return cotisationSelectionnee; }
    public void setCotisationSelectionnee(Object cotisationSelectionnee) { this.cotisationSelectionnee = cotisationSelectionnee; }
    
    public List<Cotisation> getCotisationsImpayees() { return cotisationsImpayees; }
    public void setCotisationsImpayees(List<Cotisation> cotisationsImpayees) { this.cotisationsImpayees = cotisationsImpayees; }
    
    public String getModePaiementChoisi() { return modePaiementChoisi; }
    public void setModePaiementChoisi(String modePaiementChoisi) { this.modePaiementChoisi = modePaiementChoisi; }
    
    public String getNumeroWave() { return numeroWave; }
    public void setNumeroWave(String numeroWave) { this.numeroWave = numeroWave; }
    
    public String getCommentairePaiement() { return commentairePaiement; }
    public void setCommentairePaiement(String commentairePaiement) { this.commentairePaiement = commentairePaiement; }
    
    public BigDecimal getMontantAPayer() { return montantAPayer; }
    public void setMontantAPayer(BigDecimal montantAPayer) { this.montantAPayer = montantAPayer; }
    
    public String getBanqueAssociation() { return banqueAssociation; }
    public void setBanqueAssociation(String banqueAssociation) { this.banqueAssociation = banqueAssociation; }
    
    public String getIbanAssociation() { return ibanAssociation; }
    public void setIbanAssociation(String ibanAssociation) { this.ibanAssociation = ibanAssociation; }
    
    public String getNumeroWaveAuto() { return numeroWaveAuto; }
    public void setNumeroWaveAuto(String numeroWaveAuto) { this.numeroWaveAuto = numeroWaveAuto; }
    
    public int getJourPrelevement() { return jourPrelevement; }
    public void setJourPrelevement(int jourPrelevement) { this.jourPrelevement = jourPrelevement; }
    
    public boolean isNotificationSMS() { return notificationSMS; }
    public void setNotificationSMS(boolean notificationSMS) { this.notificationSMS = notificationSMS; }
    
    public String getCotisationMensuelle() { return cotisationMensuelle; }
    public void setCotisationMensuelle(String cotisationMensuelle) { this.cotisationMensuelle = cotisationMensuelle; }
    
    public BigDecimal getTotalPayePeriode() { return totalPayePeriode; }
    public void setTotalPayePeriode(BigDecimal totalPayePeriode) { this.totalPayePeriode = totalPayePeriode; }
    
    public BigDecimal getTotalEnAttentePeriode() { return totalEnAttentePeriode; }
    public void setTotalEnAttentePeriode(BigDecimal totalEnAttentePeriode) { this.totalEnAttentePeriode = totalEnAttentePeriode; }
    
    public BigDecimal getTotalEnRetardPeriode() { return totalEnRetardPeriode; }
    public void setTotalEnRetardPeriode(BigDecimal totalEnRetardPeriode) { this.totalEnRetardPeriode = totalEnRetardPeriode; }
    
    public int getTauxConformite() { return tauxConformite; }
    public void setTauxConformite(int tauxConformite) { this.tauxConformite = tauxConformite; }
    
    public String getStatutMembre() { return statutMembre; }
    public void setStatutMembre(String statutMembre) { this.statutMembre = statutMembre; }
    
    public String getTypeMembre() { return typeMembre; }
    public void setTypeMembre(String typeMembre) { this.typeMembre = typeMembre; }
    
    public String getStatutSeverity() { return statutSeverity; }
    public void setStatutSeverity(String statutSeverity) { this.statutSeverity = statutSeverity; }
    
    public int getScorePonctualite() { return scorePonctualite; }
    public void setScorePonctualite(int scorePonctualite) { this.scorePonctualite = scorePonctualite; }
    
    public String getCommentairePonctualite() { return commentairePonctualite; }
    public void setCommentairePonctualite(String commentairePonctualite) { this.commentairePonctualite = commentairePonctualite; }
    
    public boolean isPeutPayerWave() { return true; }
    
    // Méthodes pour les charts
    public Object getHistoriquePaiementsChart() {
        // Retourner un objet chart model vide pour l'instant
        return null;
    }
    
    // Classes internes pour les données
    public static class Cotisation {
        private UUID id;
        private String reference;
        private String libelle;
        private String periode;
        private String type;
        private BigDecimal montant;
        private String statut;
        private LocalDate dateEcheance;
        private LocalDate datePaiement;
        private String modePaiement;
        
        // Getters et setters
        public UUID getId() { return id; }
        public void setId(UUID id) { this.id = id; }
        
        public String getReference() { return reference; }
        public void setReference(String reference) { this.reference = reference; }
        
        public String getLibelle() { return libelle; }
        public void setLibelle(String libelle) { this.libelle = libelle; }
        
        public String getPeriode() { return periode; }
        public void setPeriode(String periode) { this.periode = periode; }
        
        public String getType() { return type; }
        public void setType(String type) { this.type = type; }
        
        public BigDecimal getMontant() { return montant; }
        public void setMontant(BigDecimal montant) { this.montant = montant; }
        
        public String getStatut() { return statut; }
        public void setStatut(String statut) { this.statut = statut; }
        
        public LocalDate getDateEcheance() { return dateEcheance; }
        public void setDateEcheance(LocalDate dateEcheance) { this.dateEcheance = dateEcheance; }
        
        public LocalDate getDatePaiement() { return datePaiement; }
        public void setDatePaiement(LocalDate datePaiement) { this.datePaiement = datePaiement; }
        
        public String getModePaiement() { return modePaiement; }
        public void setModePaiement(String modePaiement) { this.modePaiement = modePaiement; }
        
        // Propriétés dérivées pour l'affichage
        public String getTypeSeverity() {
            return switch (type) {
                case "MENSUELLE" -> "info";
                case "SPECIALE" -> "warning";
                case "ADHESION" -> "success";
                default -> "secondary";
            };
        }
        
        public String getTypeIcon() {
            return switch (type) {
                case "MENSUELLE" -> "pi-calendar";
                case "SPECIALE" -> "pi-star";
                case "ADHESION" -> "pi-user-plus";
                default -> "pi-circle";
            };
        }
        
        public String getStatutSeverity() {
            return switch (statut) {
                case "PAYEE", "PAYE" -> "success";
                case "EN_ATTENTE" -> "warning";
                case "EN_RETARD" -> "danger";
                case "PARTIELLEMENT_PAYEE" -> "info";
                default -> "secondary";
            };
        }
        
        public String getStatutIcon() {
            return switch (statut) {
                case "PAYEE", "PAYE" -> "pi-check";
                case "EN_ATTENTE" -> "pi-clock";
                case "EN_RETARD" -> "pi-exclamation-triangle";
                case "PARTIELLEMENT_PAYEE" -> "pi-check-circle";
                default -> "pi-circle";
            };
        }
        
        public String getRetardColor() {
            return switch (statut) {
                case "EN_RETARD" -> "text-red-500";
                case "EN_ATTENTE" -> "text-orange-500";
                default -> "text-600";
            };
        }
        
        public String getStatutEcheance() {
            return switch (statut) {
                case "EN_RETARD" -> "En retard";
                case "EN_ATTENTE" -> "À venir";
                case "PAYEE", "PAYE" -> "Payée";
                case "PARTIELLEMENT_PAYEE" -> "Partiellement payée";
                default -> "Non payée";
            };
        }
        
        public String getModePaiementIcon() {
            return switch (modePaiement != null ? modePaiement : "") {
                case "Wave Money" -> "pi-mobile";
                case "Virement" -> "pi-building";
                case "Espèces" -> "pi-money-bill";
                default -> "pi-circle";
            };
        }
        
        public String getCouleurMontant() {
            return "text-900";
        }
    }
    
    public static class Echeance {
        private String libelle;
        private String periode;
        private String montant;
        private String dateEcheance;
        private String urgence;
        private String couleurUrgence;
        
        // Getters et setters
        public String getLibelle() { return libelle; }
        public void setLibelle(String libelle) { this.libelle = libelle; }
        
        public String getPeriode() { return periode; }
        public void setPeriode(String periode) { this.periode = periode; }
        
        public String getMontant() { return montant; }
        public void setMontant(String montant) { this.montant = montant; }
        
        public String getDateEcheance() { return dateEcheance; }
        public void setDateEcheance(String dateEcheance) { this.dateEcheance = dateEcheance; }
        
        public String getUrgence() { return urgence; }
        public void setUrgence(String urgence) { this.urgence = urgence; }
        
        public String getCouleurUrgence() { return couleurUrgence; }
        public void setCouleurUrgence(String couleurUrgence) { this.couleurUrgence = couleurUrgence; }
        
        public String getUrgenceSeverity() {
            return switch (urgence) {
                case "En retard" -> "danger";
                case "Bientôt" -> "warning";
                default -> "info";
            };
        }
        
        public String getCouleurMontant() {
            return "text-900";
        }
    }
}
