package dev.lions.unionflow.client.view;

import dev.lions.unionflow.server.api.dto.analytics.AnalyticsDataResponse;
import dev.lions.unionflow.client.service.AnalyticsService;
import dev.lions.unionflow.client.service.MembreService;
import dev.lions.unionflow.client.service.CotisationService;
import dev.lions.unionflow.client.service.EvenementService;
import jakarta.enterprise.context.SessionScoped;
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 dev.lions.unionflow.client.service.ErrorHandlerService;
import dev.lions.unionflow.client.service.RetryService;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.math.BigDecimal;

@Named("rapportsBean")
@SessionScoped
public class RapportsBean implements Serializable {
    
    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(RapportsBean.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_RAPPORT_DETAILS = "rapportDetailsPage";
    
    @Inject
    @RestClient
    private AnalyticsService analyticsService;
    
    @Inject
    @RestClient
    private MembreService membreService;
    
    @Inject
    @RestClient
    private CotisationService cotisationService;
    
    @Inject
    @RestClient
    private EvenementService evenementService;
    
    @Inject
    ErrorHandlerService errorHandler;
    
    @Inject
    RetryService retryService;
    
    private String organisationId; // À injecter depuis la session
    
    // Filtres de période
    private String periodeRapide;
    private LocalDate dateDebut;
    private LocalDate dateFin;
    private String groupeComparaison;
    
    // Données analytics
    private Map<String, Object> kpis;
    private Map<String, Object> evolutions;
    
    // Données calculées pour l'affichage
    private IndicateursGlobaux indicateurs;
    private List<EvolutionMensuelle> evolutionMensuelle;
    private List<Objectif> objectifs;
    private List<RepartitionMembres> repartitionMembres;
    private List<SourceRevenus> sourceRevenus;
    private List<TopEntite> topEntites;
    private List<KPI> kpisList;
    private List<Alerte> alertes;
    private List<HistoriqueRapport> historiqueRapports;
    
    private NouveauRapport nouveauRapport;
    private HistoriqueRapport rapportSelectionne;
    
    @PostConstruct
    public void init() {
        initializePeriodes();
        chargerDonnees();
    }
    
    private void initializePeriodes() {
        periodeRapide = "TRENTE_DERNIERS_JOURS";
        dateDebut = LocalDate.now().minusDays(30);
        dateFin = LocalDate.now();
        groupeComparaison = "PERIODE_PRECEDENTE";
    }
    
    /**
     * Charge les données depuis le backend
     */
    public void chargerDonnees() {
        try {
            String periode = mapperPeriode(periodeRapide);
            
            // Charger les KPIs depuis le backend
            kpis = analyticsService.obtenirTousLesKPI(organisationId, periode);
            
            // Charger les évolutions
            evolutions = analyticsService.obtenirEvolutionsKPI(organisationId, periode);
            
            // Calculer les indicateurs globaux
            calculerIndicateurs();
            
            // Calculer les répartitions
            calculerRepartitions();
            
            // Calculer les objectifs
            calculerObjectifs();
            
            // Initialiser les listes vides
            evolutionMensuelle = new ArrayList<>();
            topEntites = new ArrayList<>();
            kpisList = new ArrayList<>();
            alertes = new ArrayList<>();
            historiqueRapports = new ArrayList<>();
            
            // Convertir les KPIs en liste pour l'affichage
            convertirKPIsEnListe();
            
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du chargement des données");
            errorHandler.handleException(e, "lors du chargement des données de rapports", null);
            initialiserDonneesVides();
        }
    }
    
    /**
     * Mappe la période rapide vers le format backend
     */
    private String mapperPeriode(String periodeRapide) {
        return switch (periodeRapide) {
            case "7_JOURS" -> "SEPT_DERNIERS_JOURS";
            case "30_JOURS", "TRENTE_DERNIERS_JOURS" -> "TRENTE_DERNIERS_JOURS";
            case "3_MOIS" -> "TROIS_DERNIERS_MOIS";
            case "6_MOIS" -> "SIX_DERNIERS_MOIS";
            case "ANNEE_COURANTE" -> "CETTE_ANNEE";
            default -> "TRENTE_DERNIERS_JOURS";
        };
    }
    
    /**
     * Calcule les indicateurs globaux depuis les données réelles
     */
    private void calculerIndicateurs() {
        indicateurs = new IndicateursGlobaux();
        try {
            int totalMembres = membreService.listerTous().getData().size();
            int totalEvenements = evenementService.listerTous(0, 1000, "dateCreation", "desc").getData().size();
            
            BigDecimal totalRevenus = cotisationService.listerToutes(0, 1000).stream()
                .filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
                .map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            
            indicateurs.setTotalMembres(totalMembres);
            indicateurs.setCroissanceMembres(calculerCroissance("NOMBRE_MEMBRES_ACTIFS"));
            indicateurs.setRevenus(formatMontantCourt(totalRevenus) + " FCFA");
            indicateurs.setCroissanceRevenus(calculerCroissance("TOTAL_COTISATIONS_COLLECTEES"));
            indicateurs.setTotalEvenements(totalEvenements);
            indicateurs.setCroissanceEvenements(calculerCroissance("NOMBRE_EVENEMENTS_ORGANISES"));
            indicateurs.setTotalAides(formatMontantCourt(BigDecimal.ZERO) + " FCFA");
            indicateurs.setCroissanceAides(0.0);
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du calcul des indicateurs");
            initialiserIndicateursVides();
        }
    }
    
    /**
     * Calcule la croissance depuis les évolutions
     */
    private double calculerCroissance(String typeMetrique) {
        if (evolutions != null && evolutions.containsKey(typeMetrique)) {
            Object evolution = evolutions.get(typeMetrique);
            if (evolution instanceof BigDecimal) {
                return ((BigDecimal) evolution).doubleValue();
            } else if (evolution instanceof Number) {
                return ((Number) evolution).doubleValue();
            }
        }
        return 0.0;
    }
    
    /**
     * Calcule les répartitions
     */
    private void calculerRepartitions() {
        repartitionMembres = new ArrayList<>();
        try {
            // Corrigé: MembreResponse est dans server.api, pas client.dto; et getStatut() → getStatutCompte()
            List<dev.lions.unionflow.server.api.dto.membre.response.MembreSummaryResponse> membres = membreService.listerTous().getData();
            long actifs = membres.stream().filter(m -> "ACTIF".equals(m.getStatutCompte())).count();
            long inactifs = membres.stream().filter(m -> "INACTIF".equals(m.getStatutCompte())).count();
            long total = membres.size();
            
            if (total > 0) {
                RepartitionMembres actifsRep = new RepartitionMembres();
                actifsRep.setLibelle("Membres Actifs");
                actifsRep.setNombre((int) actifs);
                actifsRep.setPourcentage((double) actifs / total * 100.0);
                actifsRep.setCouleur("green-500");
                repartitionMembres.add(actifsRep);
                
                RepartitionMembres inactifsRep = new RepartitionMembres();
                inactifsRep.setLibelle("Membres Inactifs");
                inactifsRep.setNombre((int) inactifs);
                inactifsRep.setPourcentage((double) inactifs / total * 100.0);
                inactifsRep.setCouleur("orange-500");
                repartitionMembres.add(inactifsRep);
            }
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du calcul de la répartition des membres");
        }
        
        sourceRevenus = new ArrayList<>();
        try {
            BigDecimal totalRevenus = cotisationService.listerToutes(0, 1000).stream()
                .filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
                .map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            
            if (totalRevenus.compareTo(BigDecimal.ZERO) > 0) {
                SourceRevenus cotisations = new SourceRevenus();
                cotisations.setLibelle("Cotisations");
                cotisations.setMontant(formatMontantCourt(totalRevenus));
                cotisations.setPourcentage(100.0);
                cotisations.setCouleur("blue-500");
                cotisations.setIcon("pi-users");
                sourceRevenus.add(cotisations);
            }
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du calcul des sources de revenus");
        }
    }
    
    /**
     * Calcule les objectifs
     */
    private void calculerObjectifs() {
        objectifs = new ArrayList<>();
        try {
            int totalMembres = membreService.listerTous().getData().size();
            int totalEvenements = evenementService.listerTous(0, 1000, "dateCreation", "desc").getData().size();
            
            BigDecimal totalRevenus = cotisationService.listerToutes(0, 1000).stream()
                .filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
                .map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            
            Objectif obj1 = new Objectif();
            obj1.setLibelle("Nouveaux Membres");
            obj1.setRealise(String.valueOf(totalMembres));
            int cibleMembres = (int) (totalMembres * 1.2);
            obj1.setCible(String.valueOf(cibleMembres));
            obj1.setPourcentage(totalMembres > 0 ? (int) ((double) totalMembres / cibleMembres * 100) : 0);
            objectifs.add(obj1);
            
            Objectif obj2 = new Objectif();
            obj2.setLibelle("Revenus Cotisations");
            obj2.setRealise(formatMontantCourt(totalRevenus));
            BigDecimal cibleRevenus = totalRevenus.multiply(new BigDecimal("1.2"));
            obj2.setCible(formatMontantCourt(cibleRevenus));
            obj2.setPourcentage(totalRevenus.compareTo(BigDecimal.ZERO) > 0 ? 
                (int) (totalRevenus.divide(cibleRevenus, 2, java.math.RoundingMode.HALF_UP).doubleValue() * 100) : 0);
            objectifs.add(obj2);
            
            Objectif obj3 = new Objectif();
            obj3.setLibelle("Événements Organisés");
            obj3.setRealise(String.valueOf(totalEvenements));
            int cibleEvenements = (int) (totalEvenements * 1.2);
            obj3.setCible(String.valueOf(cibleEvenements));
            obj3.setPourcentage(totalEvenements > 0 ? (int) ((double) totalEvenements / cibleEvenements * 100) : 0);
            objectifs.add(obj3);
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du calcul des objectifs");
        }
    }
    
    /**
     * Convertit les KPIs Map en liste pour l'affichage
     */
    private void convertirKPIsEnListe() {
        kpisList = new ArrayList<>();
        if (kpis != null) {
            kpis.forEach((type, valeur) -> {
                KPI kpi = new KPI();
                kpi.setLibelle(getLibelleMetrique(type.toString()));
                kpi.setValeur(valeur instanceof BigDecimal ? 
                    ((BigDecimal) valeur).toPlainString() : valeur.toString());
                kpi.setProgression(0);
                kpi.setVariation(calculerCroissance(type.toString()));
                kpi.setTendance(kpi.getVariation() > 0 ? "HAUSSE" : kpi.getVariation() < 0 ? "BAISSE" : "STABLE");
                kpi.setIcon(getIconeMetrique(type.toString()));
                kpi.setCouleur(getCouleurMetrique(type.toString()));
                kpisList.add(kpi);
            });
        }
    }
    
    private String getLibelleMetrique(String type) {
        return switch (type) {
            case "NOMBRE_MEMBRES_ACTIFS" -> "Membres Actifs";
            case "TOTAL_COTISATIONS_COLLECTEES" -> "Cotisations Collectées";
            case "NOMBRE_EVENEMENTS_ORGANISES" -> "Événements Organisés";
            default -> type;
        };
    }
    
    private String getIconeMetrique(String type) {
        return switch (type) {
            case "NOMBRE_MEMBRES_ACTIFS" -> "pi-users";
            case "TOTAL_COTISATIONS_COLLECTEES" -> "pi-dollar";
            case "NOMBRE_EVENEMENTS_ORGANISES" -> "pi-calendar";
            default -> "pi-chart-bar";
        };
    }
    
    private String getCouleurMetrique(String type) {
        return switch (type) {
            case "NOMBRE_MEMBRES_ACTIFS" -> "blue-500";
            case "TOTAL_COTISATIONS_COLLECTEES" -> "green-500";
            case "NOMBRE_EVENEMENTS_ORGANISES" -> "orange-500";
            default -> "gray-500";
        };
    }
    
    private String formatMontantCourt(BigDecimal montant) {
        if (montant == null) return "0";
        double millions = montant.doubleValue() / 1_000_000.0;
        if (millions >= 1) {
            return String.format("%.1fM", millions);
        }
        return String.format("%.0fK", montant.doubleValue() / 1_000.0);
    }
    
    private void initialiserDonneesVides() {
        indicateurs = new IndicateursGlobaux();
        initialiserIndicateursVides();
        evolutionMensuelle = new ArrayList<>();
        objectifs = new ArrayList<>();
        repartitionMembres = new ArrayList<>();
        sourceRevenus = new ArrayList<>();
        topEntites = new ArrayList<>();
        kpisList = new ArrayList<>();
        alertes = new ArrayList<>();
        historiqueRapports = new ArrayList<>();
    }
    
    private void initialiserIndicateursVides() {
        indicateurs.setTotalMembres(0);
        indicateurs.setCroissanceMembres(0.0);
        indicateurs.setRevenus("0 FCFA");
        indicateurs.setCroissanceRevenus(0.0);
        indicateurs.setTotalEvenements(0);
        indicateurs.setCroissanceEvenements(0.0);
        indicateurs.setTotalAides("0 FCFA");
        indicateurs.setCroissanceAides(0.0);
    }
    
    /**
     * Actualise les données
     */
    public void actualiser() {
        chargerDonnees();
        errorHandler.showSuccess("Succès", "Données actualisées avec succès.");
    }
    
    /**
     * Génère un nouveau rapport
     */
    public void genererRapport() {
        LOG.infof("Génération du rapport %s en format %s", nouveauRapport.getType(), nouveauRapport.getFormat());
        
        HistoriqueRapport nouveauHistorique = new HistoriqueRapport();
        nouveauHistorique.setId(UUID.randomUUID());
        nouveauHistorique.setType(nouveauRapport.getType());
        nouveauHistorique.setTypeLibelle(getTypeLibelle(nouveauRapport.getType()));
        nouveauHistorique.setTypeIcon(getTypeIcon(nouveauRapport.getType()));
        nouveauHistorique.setTypeCouleur(getTypeCouleur(nouveauRapport.getType()));
        nouveauHistorique.setDateGeneration(LocalDate.now());
        nouveauHistorique.setPeriodeCouverte(getPeriodeDescription(nouveauRapport.getPeriode()));
        nouveauHistorique.setGenerePar("Utilisateur Actuel");
        nouveauHistorique.setStatut("EN_COURS");
        
        historiqueRapports.add(0, nouveauHistorique);
        initializeNouveauRapport();
        errorHandler.showSuccess("Succès", "Rapport en cours de génération.");
    }
    
    private void initializeNouveauRapport() {
        nouveauRapport = new NouveauRapport();
        nouveauRapport.setFormat("PDF");
        nouveauRapport.setPeriode("30_JOURS");
        nouveauRapport.setDetail("STANDARD");
    }
    
    private String getTypeLibelle(String type) {
        return switch (type) {
            case "FINANCIER" -> "Rapport Financier";
            case "MEMBRES" -> "Rapport Membres";
            case "ACTIVITES" -> "Rapport Activités";
            case "PERFORMANCE" -> "Rapport Performance";
            case "COMPLET" -> "Rapport Complet";
            default -> type;
        };
    }
    
    private String getTypeIcon(String type) {
        return switch (type) {
            case "FINANCIER" -> "pi-dollar";
            case "MEMBRES" -> "pi-users";
            case "ACTIVITES" -> "pi-calendar";
            case "PERFORMANCE" -> "pi-chart-bar";
            case "COMPLET" -> "pi-file";
            default -> "pi-file";
        };
    }
    
    private String getTypeCouleur(String type) {
        return switch (type) {
            case "FINANCIER" -> "green-500";
            case "MEMBRES" -> "blue-500";
            case "ACTIVITES" -> "orange-500";
            case "PERFORMANCE" -> "purple-500";
            case "COMPLET" -> "indigo-500";
            default -> "gray-500";
        };
    }
    
    private String getPeriodeDescription(String periode) {
        return switch (periode) {
            case "7_JOURS" -> "7 derniers jours";
            case "30_JOURS" -> "30 derniers jours";
            case "3_MOIS" -> "3 derniers mois";
            case "6_MOIS" -> "6 derniers mois";
            case "ANNEE_COURANTE" -> "Année en cours";
            case "PERSONNALISEE" -> "Période personnalisée";
            default -> periode;
        };
    }
    
    public String voirRapport(HistoriqueRapport rapport) {
        rapportSelectionne = rapport;
        // Utilisation de navigation outcome au lieu de chemin direct (WOU/DRY)
        return OUTCOME_RAPPORT_DETAILS + "?faces-redirect=true";
    }
    
    public void telechargerRapport(HistoriqueRapport rapport) {
        LOG.infof("Téléchargement du rapport: %s", rapport.getTypeLibelle());
        errorHandler.showInfo("Téléchargement", "Le téléchargement du rapport va commencer.");
    }
    
    public void exporterDonnees() {
        LOG.info("Export des données statistiques");
        errorHandler.showInfo("Export", "L'export des données va commencer.");
    }
    
    // Getters et Setters
    public String getPeriodeRapide() { return periodeRapide; }
    public void setPeriodeRapide(String periodeRapide) { 
        this.periodeRapide = periodeRapide;
        chargerDonnees();
    }
    
    public LocalDate getDateDebut() { return dateDebut; }
    public void setDateDebut(LocalDate dateDebut) { this.dateDebut = dateDebut; }
    
    public LocalDate getDateFin() { return dateFin; }
    public void setDateFin(LocalDate dateFin) { this.dateFin = dateFin; }
    
    public String getGroupeComparaison() { return groupeComparaison; }
    public void setGroupeComparaison(String groupeComparaison) { this.groupeComparaison = groupeComparaison; }
    
    public IndicateursGlobaux getIndicateurs() { return indicateurs; }
    public void setIndicateurs(IndicateursGlobaux indicateurs) { this.indicateurs = indicateurs; }
    
    public List<EvolutionMensuelle> getEvolutionMensuelle() { return evolutionMensuelle; }
    public void setEvolutionMensuelle(List<EvolutionMensuelle> evolutionMensuelle) { this.evolutionMensuelle = evolutionMensuelle; }
    
    public List<Objectif> getObjectifs() { return objectifs; }
    public void setObjectifs(List<Objectif> objectifs) { this.objectifs = objectifs; }
    
    public List<RepartitionMembres> getRepartitionMembres() { return repartitionMembres; }
    public void setRepartitionMembres(List<RepartitionMembres> repartitionMembres) { this.repartitionMembres = repartitionMembres; }
    
    public List<SourceRevenus> getSourceRevenus() { return sourceRevenus; }
    public void setSourceRevenus(List<SourceRevenus> sourceRevenus) { this.sourceRevenus = sourceRevenus; }
    
    public List<TopEntite> getTopEntites() { return topEntites; }
    public void setTopEntites(List<TopEntite> topEntites) { this.topEntites = topEntites; }
    
    public List<KPI> getKpis() { return kpisList; }
    public void setKpis(List<KPI> kpis) { this.kpisList = kpis; }
    
    public List<Alerte> getAlertes() { return alertes; }
    public void setAlertes(List<Alerte> alertes) { this.alertes = alertes; }
    
    public List<HistoriqueRapport> getHistoriqueRapports() { return historiqueRapports; }
    public void setHistoriqueRapports(List<HistoriqueRapport> historiqueRapports) { this.historiqueRapports = historiqueRapports; }
    
    public NouveauRapport getNouveauRapport() { return nouveauRapport; }
    public void setNouveauRapport(NouveauRapport nouveauRapport) { this.nouveauRapport = nouveauRapport; }
    
    public HistoriqueRapport getRapportSelectionne() { return rapportSelectionne; }
    public void setRapportSelectionne(HistoriqueRapport rapportSelectionne) { this.rapportSelectionne = rapportSelectionne; }
    
    // Classes internes (conservées pour compatibilité avec les pages XHTML)
    public static class IndicateursGlobaux {
        private int totalMembres;
        private double croissanceMembres;
        private String revenus;
        private double croissanceRevenus;
        private int totalEvenements;
        private double croissanceEvenements;
        private String totalAides;
        private double croissanceAides;
        
        public int getTotalMembres() { return totalMembres; }
        public void setTotalMembres(int totalMembres) { this.totalMembres = totalMembres; }
        
        public double getCroissanceMembres() { return croissanceMembres; }
        public void setCroissanceMembres(double croissanceMembres) { this.croissanceMembres = croissanceMembres; }
        
        public String getRevenus() { return revenus; }
        public void setRevenus(String revenus) { this.revenus = revenus; }
        
        public double getCroissanceRevenus() { return croissanceRevenus; }
        public void setCroissanceRevenus(double croissanceRevenus) { this.croissanceRevenus = croissanceRevenus; }
        
        public int getTotalEvenements() { return totalEvenements; }
        public void setTotalEvenements(int totalEvenements) { this.totalEvenements = totalEvenements; }
        
        public double getCroissanceEvenements() { return croissanceEvenements; }
        public void setCroissanceEvenements(double croissanceEvenements) { this.croissanceEvenements = croissanceEvenements; }
        
        public String getTotalAides() { return totalAides; }
        public void setTotalAides(String totalAides) { this.totalAides = totalAides; }
        
        public double getCroissanceAides() { return croissanceAides; }
        public void setCroissanceAides(double croissanceAides) { this.croissanceAides = croissanceAides; }
    }
    
    public static class EvolutionMensuelle {
        private String libelle;
        private int membres;
        private double revenus;
        private int hauteurMembres;
        private int hauteurRevenus;
        
        public String getLibelle() { return libelle; }
        public void setLibelle(String libelle) { this.libelle = libelle; }
        
        public int getMembres() { return membres; }
        public void setMembres(int membres) { this.membres = membres; }
        
        public double getRevenus() { return revenus; }
        public void setRevenus(double revenus) { this.revenus = revenus; }
        
        public int getHauteurMembres() { return hauteurMembres; }
        public void setHauteurMembres(int hauteurMembres) { this.hauteurMembres = hauteurMembres; }
        
        public int getHauteurRevenus() { return hauteurRevenus; }
        public void setHauteurRevenus(int hauteurRevenus) { this.hauteurRevenus = hauteurRevenus; }
    }
    
    public static class Objectif {
        private String libelle;
        private String realise;
        private String cible;
        private int pourcentage;
        
        public String getLibelle() { return libelle; }
        public void setLibelle(String libelle) { this.libelle = libelle; }
        
        public String getRealise() { return realise; }
        public void setRealise(String realise) { this.realise = realise; }
        
        public String getCible() { return cible; }
        public void setCible(String cible) { this.cible = cible; }
        
        public int getPourcentage() { return pourcentage; }
        public void setPourcentage(int pourcentage) { this.pourcentage = pourcentage; }
    }
    
    public static class RepartitionMembres {
        private String libelle;
        private int nombre;
        private double pourcentage;
        private String couleur;
        
        public String getLibelle() { return libelle; }
        public void setLibelle(String libelle) { this.libelle = libelle; }
        
        public int getNombre() { return nombre; }
        public void setNombre(int nombre) { this.nombre = nombre; }
        
        public double getPourcentage() { return pourcentage; }
        public void setPourcentage(double pourcentage) { this.pourcentage = pourcentage; }
        
        public String getCouleur() { return couleur; }
        public void setCouleur(String couleur) { this.couleur = couleur; }
    }
    
    public static class SourceRevenus {
        private String libelle;
        private String montant;
        private double pourcentage;
        private String couleur;
        private String icon;
        
        public String getLibelle() { return libelle; }
        public void setLibelle(String libelle) { this.libelle = libelle; }
        
        public String getMontant() { return montant; }
        public void setMontant(String montant) { this.montant = montant; }
        
        public double getPourcentage() { return pourcentage; }
        public void setPourcentage(double pourcentage) { this.pourcentage = pourcentage; }
        
        public String getCouleur() { return couleur; }
        public void setCouleur(String couleur) { this.couleur = couleur; }
        
        public String getIcon() { return icon; }
        public void setIcon(String icon) { this.icon = icon; }
    }
    
    public static class TopEntite {
        private int rang;
        private String nom;
        private String typeIcon;
        private int score;
        private String tendance;
        
        public int getRang() { return rang; }
        public void setRang(int rang) { this.rang = rang; }
        
        public String getNom() { return nom; }
        public void setNom(String nom) { this.nom = nom; }
        
        public String getTypeIcon() { return typeIcon; }
        public void setTypeIcon(String typeIcon) { this.typeIcon = typeIcon; }
        
        public int getScore() { return score; }
        public void setScore(int score) { this.score = score; }
        
        public String getTendance() { return tendance; }
        public void setTendance(String tendance) { this.tendance = tendance; }
    }
    
    public static class KPI {
        private String libelle;
        private String valeur;
        private int progression;
        private double variation;
        private String tendance;
        private String icon;
        private String couleur;
        
        public String getLibelle() { return libelle; }
        public void setLibelle(String libelle) { this.libelle = libelle; }
        
        public String getValeur() { return valeur; }
        public void setValeur(String valeur) { this.valeur = valeur; }
        
        public int getProgression() { return progression; }
        public void setProgression(int progression) { this.progression = progression; }
        
        public double getVariation() { return variation; }
        public void setVariation(double variation) { this.variation = variation; }
        
        public String getTendance() { return tendance; }
        public void setTendance(String tendance) { this.tendance = tendance; }
        
        public String getIcon() { return icon; }
        public void setIcon(String icon) { this.icon = icon; }
        
        public String getCouleur() { return couleur; }
        public void setCouleur(String couleur) { this.couleur = couleur; }
    }
    
    public static class Alerte {
        private String titre;
        private String description;
        private String priorite;
        private String severite;
        private String severiteCouleur;
        private String icon;
        private String dateDetection;
        
        public String getTitre() { return titre; }
        public void setTitre(String titre) { this.titre = titre; }
        
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        
        public String getPriorite() { return priorite; }
        public void setPriorite(String priorite) { this.priorite = priorite; }
        
        public String getSeverite() { return severite; }
        public void setSeverite(String severite) { this.severite = severite; }
        
        public String getSeveriteCouleur() { return severiteCouleur; }
        public void setSeveriteCouleur(String severiteCouleur) { this.severiteCouleur = severiteCouleur; }
        
        public String getIcon() { return icon; }
        public void setIcon(String icon) { this.icon = icon; }
        
        public String getDateDetection() { return dateDetection; }
        public void setDateDetection(String dateDetection) { this.dateDetection = dateDetection; }
    }
    
    public static class HistoriqueRapport {
        private UUID id;
        private String type;
        private String typeLibelle;
        private String typeIcon;
        private String typeCouleur;
        private LocalDate dateGeneration;
        private String periodeCouverte;
        private String generePar;
        private String statut;
        
        public UUID getId() { return id; }
        public void setId(UUID id) { this.id = id; }
        
        public String getType() { return type; }
        public void setType(String type) { this.type = type; }
        
        public String getTypeLibelle() { return typeLibelle; }
        public void setTypeLibelle(String typeLibelle) { this.typeLibelle = typeLibelle; }
        
        public String getTypeIcon() { return typeIcon; }
        public void setTypeIcon(String typeIcon) { this.typeIcon = typeIcon; }
        
        public String getTypeCouleur() { return typeCouleur; }
        public void setTypeCouleur(String typeCouleur) { this.typeCouleur = typeCouleur; }
        
        public LocalDate getDateGeneration() { return dateGeneration; }
        public void setDateGeneration(LocalDate dateGeneration) { this.dateGeneration = dateGeneration; }
        
        public String getPeriodeCouverte() { return periodeCouverte; }
        public void setPeriodeCouverte(String periodeCouverte) { this.periodeCouverte = periodeCouverte; }
        
        public String getGenerePar() { return generePar; }
        public void setGenerePar(String generePar) { this.generePar = generePar; }
        
        public String getStatut() { return statut; }
        public void setStatut(String statut) { this.statut = statut; }
        
        public String getDateGenerationFormatee() {
            if (dateGeneration == null) return "";
            return dateGeneration.format(DATE_FORMATTER);
        }
        
        public String getStatutSeverity() {
            return switch (statut) {
                case "GENERE" -> "success";
                case "EN_COURS" -> "warning";
                case "PLANIFIE" -> "info";
                case "ERREUR" -> "danger";
                default -> "secondary";
            };
        }
    }
    
    public static class NouveauRapport {
        private String type;
        private String format;
        private String periode;
        private String detail;
        private String commentaires;
        
        public String getType() { return type; }
        public void setType(String type) { this.type = type; }
        
        public String getFormat() { return format; }
        public void setFormat(String format) { this.format = format; }
        
        public String getPeriode() { return periode; }
        public void setPeriode(String periode) { this.periode = periode; }
        
        public String getDetail() { return detail; }
        public void setDetail(String detail) { this.detail = detail; }
        
        public String getCommentaires() { return commentaires; }
        public void setCommentaires(String commentaires) { this.commentaires = commentaires; }
    }
}
