package dev.lions.btpxpress.view;

import com.fasterxml.jackson.databind.JsonNode;
import jakarta.annotation.PostConstruct;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import dev.lions.btpxpress.service.DashboardService;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Bean de vue pour le tableau de bord principal optimisé BTP Xpress.
 *
 * <p><strong>Architecture 2025 - Dashboard Complet</strong></p>
 *
 * <p>Ce bean orchestre l'affichage du tableau de bord professionnel couvrant
 * TOUS les aspects métiers de BTP Xpress :</p>
 * <ul>
 *   <li><strong>Chantiers</strong>: Vue globale, actifs, en retard, budget, avancement</li>
 *   <li><strong>Ressources Humaines</strong>: Employés actifs, équipes, disponibilités en attente</li>
 *   <li><strong>Matériel</strong>: Disponibilité, maintenance, alertes critiques</li>
 *   <li><strong>Planning</strong>: Événements du jour, conflits détectés</li>
 *   <li><strong>Finances</strong>: Budget vs coût réel, analyse par chantier</li>
 *   <li><strong>Maintenance</strong>: En retard, planifiées, alertes</li>
 *   <li><strong>Documents</strong>: Accès rapide aux 5 derniers documents</li>
 *   <li><strong>Alertes</strong>: Vue consolidée de tout ce qui nécessite attention immédiate</li>
 * </ul>
 *
 * <p><strong>Principe fondamental</strong> : AUCUNE donnée fictive. Toutes les données
 * proviennent strictement de l'API backend via les endpoints {@code /api/v1/dashboard/*}</p>
 *
 * <p>Voir {@code DASHBOARD_CONCEPTION.md} pour la documentation détaillée de l'architecture.</p>
 *
 * @author BTP Xpress Development Team
 * @version 2.0.0 - Dashboard optimisé
 * @since 1.0.0
 */
@Named("dashboardView")
@ViewScoped
@Getter
@Setter
public class DashboardView implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger logger = LoggerFactory.getLogger(DashboardView.class);

    /**
     * Format de date français : dd/MM/yyyy
     */
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");

    /**
     * Format de date-heure français : dd/MM/yyyy HH:mm
     */
    private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");

    @Inject
    private DashboardService dashboardService;

    // ============================================================================
    // MÉTRIQUES PRINCIPALES (KPIs en haut du dashboard)
    // ============================================================================

    /**
     * Nombre total de chantiers dans le système
     */
    private long nombreChantiers = 0;

    /**
     * Nombre de chantiers actifs (EN_COURS + PLANIFIE)
     */
    private long chantiersActifs = 0;

    /**
     * Taux d'activité des chantiers en pourcentage
     */
    private double tauxActiviteChantiers = 0.0;

    /**
     * Nombre total d'équipes
     */
    private long nombreEquipes = 0;

    /**
     * Nombre d'équipes disponibles
     */
    private long equipesDisponibles = 0;

    /**
     * Taux de disponibilité des équipes en pourcentage
     */
    private double tauxDisponibiliteEquipes = 0.0;

    /**
     * Nombre de maintenances en retard (ALERTE CRITIQUE)
     */
    private long maintenancesEnRetard = 0;

    /**
     * Nombre de maintenances planifiées
     */
    private long maintenancesPlanifiees = 0;

    /**
     * Indicateur d'alerte de retard de maintenance
     */
    private boolean alerteRetardMaintenance = false;

    // ============================================================================
    // MÉTRIQUES RESSOURCES
    // ============================================================================

    /**
     * Nombre total d'employés
     */
    private long nombreEmployes = 0;

    /**
     * Nombre d'employés actifs
     */
    private long employesActifs = 0;

    /**
     * Taux d'activité des employés en pourcentage
     */
    private double tauxActiviteEmployes = 0.0;

    /**
     * Nombre total de matériel
     */
    private long nombreMateriel = 0;

    /**
     * Nombre de matériel disponible
     */
    private long materielDisponible = 0;

    /**
     * Taux de disponibilité du matériel en pourcentage
     */
    private double tauxDisponibiliteMateriel = 0.0;

    /**
     * Nombre de disponibilités (congés, absences) en attente de validation
     */
    private long disponibilitesEnAttenteCount = 0;

    // ============================================================================
    // MÉTRIQUES PLANNING
    // ============================================================================

    /**
     * Nombre d'événements de planning aujourd'hui
     */
    private long evenementsAujourdhui = 0;

    /**
     * Nombre de conflits de planning détectés sur les 7 prochains jours
     */
    private long conflitsPlanningCount = 0;

    // ============================================================================
    // MÉTRIQUES DOCUMENTS
    // ============================================================================

    /**
     * Nombre total de documents dans le système
     */
    private long nombreDocuments = 0;

    // ============================================================================
    // ALERTES CONSOLIDÉES
    // ============================================================================

    /**
     * Nombre total d'alertes nécessitant une attention immédiate
     */
    private long totalAlertes = 0;

    /**
     * Indicateur d'alerte critique (true si au moins une alerte)
     */
    private boolean alerteCritique = false;

    /**
     * Nombre d'alertes de maintenance
     */
    private long alertesMaintenanceCount = 0;

    /**
     * Nombre d'alertes de chantiers en retard
     */
    private long alertesChantiersCount = 0;

    /**
     * Nombre d'alertes de disponibilités en attente
     */
    private long alertesDisponibilitesCount = 0;

    /**
     * Nombre d'alertes de conflits de planning
     */
    private long alertesConflitsCount = 0;

    // ============================================================================
    // LISTES DE DONNÉES POUR AFFICHAGE
    // ============================================================================

    /**
     * Liste des chantiers actifs avec toutes leurs informations
     */
    private List<ChantierResume> chantiersActifsList = new ArrayList<>();

    /**
     * Liste des chantiers en retard
     */
    private List<ChantierEnRetard> chantiersEnRetardList = new ArrayList<>();

    /**
     * Liste des maintenances en retard
     */
    private List<MaintenanceEnRetard> maintenancesEnRetardList = new ArrayList<>();

    /**
     * Liste des disponibilités en attente de validation
     */
    private List<DisponibiliteEnAttente> disponibilitesEnAttenteList = new ArrayList<>();

    /**
     * Liste des 5 documents les plus récents
     */
    private List<DocumentRecent> documentsRecentsList = new ArrayList<>();

    /**
     * Initialise le dashboard en chargeant toutes les données depuis l'API backend.
     *
     * <p>Cette méthode est appelée automatiquement après la construction du bean (PostConstruct).
     * Elle orchestre le chargement de toutes les métriques et données via le DashboardService.</p>
     *
     * <p><strong>Endpoints API appelés</strong> :</p>
     * <ul>
     *   <li>{@code GET /api/v1/dashboard} - Métriques principales</li>
     *   <li>{@code GET /api/v1/dashboard/chantiers} - Chantiers actifs et en retard</li>
     *   <li>{@code GET /api/v1/dashboard/ressources} - Ressources humaines et matérielles</li>
     *   <li>{@code GET /api/v1/dashboard/maintenance} - Maintenances</li>
     *   <li>{@code GET /api/v1/dashboard/alertes} - Alertes consolidées</li>
     * </ul>
     */
    @PostConstruct
    public void init() {
        logger.info("═══════════════════════════════════════════════════════════════");
        logger.info("Initialisation du Dashboard BTP Xpress - Version 2.0 Optimisée");
        logger.info("═══════════════════════════════════════════════════════════════");

        // Chargement séquentiel des différentes sections du dashboard
        loadDashboardPrincipal();
        loadDashboardChantiers();
        loadDashboardRessources();
        loadDashboardMaintenance();
        loadAlertes();

        logger.info("✓ Dashboard initialisé avec succès - {} alertes détectées", totalAlertes);
    }

    /**
     * Charge les métriques du dashboard principal depuis l'API.
     *
     * <p>Récupère les KPIs globaux affichés en haut du dashboard :</p>
     * <ul>
     *   <li>Chantiers : total, actifs, taux d'activité</li>
     *   <li>Équipes : total, disponibles, taux de disponibilité</li>
     *   <li>Employés : total, actifs, taux d'activité</li>
     *   <li>Matériel : total, disponible, taux de disponibilité</li>
     *   <li>Maintenance : en retard, planifiées, alerte</li>
     *   <li>Planning : événements aujourd'hui</li>
     *   <li>Documents : total, récents</li>
     * </ul>
     *
     * <p><strong>Endpoint</strong> : {@code GET /api/v1/dashboard}</p>
     */
    private void loadDashboardPrincipal() {
        try {
            logger.debug("→ Chargement dashboard principal...");
            JsonNode dashboard = dashboardService.getDashboardPrincipal();

            if (dashboard != null) {
                // Métriques chantiers
                JsonNode chantiers = dashboard.get("chantiers");
                if (chantiers != null) {
                    nombreChantiers = chantiers.get("total").asLong(0);
                    chantiersActifs = chantiers.get("actifs").asLong(0);
                    tauxActiviteChantiers = chantiers.get("tauxActivite").asDouble(0.0);
                    logger.debug("  ✓ Chantiers: {} total, {} actifs ({} %)",
                        nombreChantiers, chantiersActifs, String.format("%.1f", tauxActiviteChantiers));
                }

                // Métriques équipes
                JsonNode equipes = dashboard.get("equipes");
                if (equipes != null) {
                    nombreEquipes = equipes.get("total").asLong(0);
                    equipesDisponibles = equipes.get("disponibles").asLong(0);
                    tauxDisponibiliteEquipes = equipes.get("tauxDisponibilite").asDouble(0.0);
                    logger.debug("  ✓ Équipes: {} total, {} disponibles ({} %)",
                        nombreEquipes, equipesDisponibles, String.format("%.1f", tauxDisponibiliteEquipes));
                }

                // Métriques employés
                JsonNode employes = dashboard.get("employes");
                if (employes != null) {
                    nombreEmployes = employes.get("total").asLong(0);
                    employesActifs = employes.get("actifs").asLong(0);
                    tauxActiviteEmployes = employes.get("tauxActivite").asDouble(0.0);
                    logger.debug("  ✓ Employés: {} total, {} actifs ({} %)",
                        nombreEmployes, employesActifs, String.format("%.1f", tauxActiviteEmployes));
                }

                // Métriques matériel
                JsonNode materiel = dashboard.get("materiel");
                if (materiel != null) {
                    nombreMateriel = materiel.get("total").asLong(0);
                    materielDisponible = materiel.get("disponible").asLong(0);
                    tauxDisponibiliteMateriel = materiel.get("tauxDisponibilite").asDouble(0.0);
                    logger.debug("  ✓ Matériel: {} total, {} disponible ({} %)",
                        nombreMateriel, materielDisponible, String.format("%.1f", tauxDisponibiliteMateriel));
                }

                // Métriques maintenance
                JsonNode maintenance = dashboard.get("maintenance");
                if (maintenance != null) {
                    maintenancesEnRetard = maintenance.get("enRetard").asLong(0);
                    maintenancesPlanifiees = maintenance.get("planifiees").asLong(0);
                    alerteRetardMaintenance = maintenance.get("alerteRetard").asBoolean(false);
                    logger.debug("  ✓ Maintenance: {} en retard, {} planifiées [Alerte: {}]",
                        maintenancesEnRetard, maintenancesPlanifiees, alerteRetardMaintenance);
                }

                // Métriques planning
                JsonNode planning = dashboard.get("planning");
                if (planning != null) {
                    evenementsAujourdhui = planning.get("evenementsAujourdhui").asLong(0);
                    disponibilitesEnAttenteCount = planning.get("disponibilitesEnAttente").asLong(0);
                    logger.debug("  ✓ Planning: {} événements aujourd'hui, {} disponibilités en attente",
                        evenementsAujourdhui, disponibilitesEnAttenteCount);
                }

                // Métriques documents
                JsonNode documents = dashboard.get("documents");
                if (documents != null) {
                    nombreDocuments = documents.get("total").asLong(0);

                    // Documents récents
                    JsonNode recentsNode = documents.get("recents");
                    if (recentsNode != null && recentsNode.isArray()) {
                        documentsRecentsList.clear();
                        Iterator<JsonNode> iterator = recentsNode.elements();
                        while (iterator.hasNext()) {
                            JsonNode doc = iterator.next();
                            DocumentRecent docRecent = new DocumentRecent();
                            docRecent.setId(doc.get("id").asText());
                            docRecent.setNom(doc.get("nom").asText());
                            docRecent.setType(doc.get("type").asText());

                            String dateCreationStr = doc.get("dateCreation").asText();
                            try {
                                docRecent.setDateCreation(LocalDateTime.parse(dateCreationStr));
                            } catch (Exception e) {
                                logger.warn("Erreur parsing date document: {}", dateCreationStr);
                            }

                            documentsRecentsList.add(docRecent);
                        }
                    }
                    logger.debug("  ✓ Documents: {} total, {} récents chargés",
                        nombreDocuments, documentsRecentsList.size());
                }
            } else {
                logger.warn("⚠ Dashboard principal: réponse null de l'API");
            }
        } catch (Exception e) {
            logger.error("❌ Erreur lors du chargement du dashboard principal", e);
        }
    }

    /**
     * Charge les métriques et listes des chantiers depuis l'API.
     *
     * <p>Récupère :</p>
     * <ul>
     *   <li>Liste complète des chantiers actifs (EN_COURS + PLANIFIE)</li>
     *   <li>Liste des chantiers en retard (date fin prévue dépassée)</li>
     * </ul>
     *
     * <p><strong>Endpoint</strong> : {@code GET /api/v1/dashboard/chantiers}</p>
     */
    private void loadDashboardChantiers() {
        try {
            logger.debug("→ Chargement dashboard chantiers...");
            JsonNode dashboard = dashboardService.getDashboardChantiers();

            if (dashboard != null) {
                // Chantiers actifs
                JsonNode chantiersActifsNode = dashboard.get("chantiersActifs");
                if (chantiersActifsNode != null && chantiersActifsNode.isArray()) {
                    chantiersActifsList.clear();
                    Iterator<JsonNode> iterator = chantiersActifsNode.elements();

                    while (iterator.hasNext()) {
                        JsonNode chantier = iterator.next();
                        ChantierResume c = new ChantierResume();
                        c.setId(chantier.get("id").asText());
                        c.setNom(chantier.get("nom").asText(""));
                        c.setAdresse(chantier.get("adresse").asText(""));
                        c.setClient(chantier.get("client").asText("Non assigné"));

                        // Dates
                        if (chantier.has("dateDebut") && !chantier.get("dateDebut").isNull()) {
                            try {
                                c.setDateDebut(LocalDate.parse(chantier.get("dateDebut").asText()));
                            } catch (Exception e) {
                                logger.warn("Erreur parsing dateDebut: {}", chantier.get("dateDebut").asText());
                            }
                        }
                        if (chantier.has("dateFinPrevue") && !chantier.get("dateFinPrevue").isNull()) {
                            try {
                                c.setDateFinPrevue(LocalDate.parse(chantier.get("dateFinPrevue").asText()));
                            } catch (Exception e) {
                                logger.warn("Erreur parsing dateFinPrevue: {}", chantier.get("dateFinPrevue").asText());
                            }
                        }

                        // Métriques
                        c.setStatut(chantier.get("statut").asText(""));
                        c.setBudget(chantier.get("budget").asDouble(0.0));
                        c.setCoutReel(chantier.get("coutReel").asDouble(0.0));
                        c.setAvancement(chantier.get("avancement").asInt(0));

                        chantiersActifsList.add(c);
                    }

                    logger.debug("  ✓ {} chantiers actifs chargés", chantiersActifsList.size());
                }

                // Chantiers en retard
                JsonNode chantiersEnRetardNode = dashboard.get("chantiersEnRetard");
                if (chantiersEnRetardNode != null && chantiersEnRetardNode.isArray()) {
                    chantiersEnRetardList.clear();
                    Iterator<JsonNode> iterator = chantiersEnRetardNode.elements();

                    while (iterator.hasNext()) {
                        JsonNode chantier = iterator.next();
                        ChantierEnRetard c = new ChantierEnRetard();
                        c.setId(chantier.get("id").asText());
                        c.setNom(chantier.get("nom").asText(""));

                        if (chantier.has("dateFinPrevue") && !chantier.get("dateFinPrevue").isNull()) {
                            try {
                                c.setDateFinPrevue(LocalDate.parse(chantier.get("dateFinPrevue").asText()));
                            } catch (Exception e) {
                                logger.warn("Erreur parsing dateFinPrevue retard: {}", chantier.get("dateFinPrevue").asText());
                            }
                        }

                        c.setJoursRetard(chantier.get("joursRetard").asLong(0));
                        chantiersEnRetardList.add(c);
                    }

                    logger.debug("  ✓ {} chantiers en retard chargés", chantiersEnRetardList.size());
                }
            } else {
                logger.warn("⚠ Dashboard chantiers: réponse null de l'API");
            }
        } catch (Exception e) {
            logger.error("❌ Erreur lors du chargement du dashboard chantiers", e);
        }
    }

    /**
     * Charge les métriques des ressources (RH et matérielles) depuis l'API.
     *
     * <p>Récupère :</p>
     * <ul>
     *   <li>Statistiques des équipes (déjà chargées dans principal)</li>
     *   <li>Statistiques des employés (déjà chargées dans principal)</li>
     *   <li>Statistiques du matériel (déjà chargées dans principal)</li>
     *   <li>Liste des disponibilités en attente (congés, absences à valider)</li>
     * </ul>
     *
     * <p><strong>Endpoint</strong> : {@code GET /api/v1/dashboard/ressources}</p>
     */
    private void loadDashboardRessources() {
        try {
            logger.debug("→ Chargement dashboard ressources...");
            JsonNode ressources = dashboardService.getDashboardRessources();

            if (ressources != null) {
                // Les statistiques équipes/employés/matériel sont déjà chargées dans loadDashboardPrincipal
                // Ici on charge les disponibilités en attente

                JsonNode disponibilites = ressources.get("disponibilites");
                if (disponibilites != null) {
                    JsonNode enAttenteDetails = disponibilites.get("enAttenteDetails");
                    if (enAttenteDetails != null && enAttenteDetails.isArray()) {
                        disponibilitesEnAttenteList.clear();
                        Iterator<JsonNode> iterator = enAttenteDetails.elements();

                        while (iterator.hasNext()) {
                            JsonNode dispo = iterator.next();
                            DisponibiliteEnAttente d = new DisponibiliteEnAttente();
                            d.setId(dispo.get("id").asText());
                            d.setEmploye(dispo.get("employe").asText(""));
                            d.setType(dispo.get("type").asText(""));
                            d.setMotif(dispo.get("motif").asText(""));

                            try {
                                d.setDateDebut(LocalDateTime.parse(dispo.get("dateDebut").asText()));
                                d.setDateFin(LocalDateTime.parse(dispo.get("dateFin").asText()));
                            } catch (Exception e) {
                                logger.warn("Erreur parsing dates disponibilité");
                            }

                            disponibilitesEnAttenteList.add(d);
                        }

                        logger.debug("  ✓ {} disponibilités en attente chargées", disponibilitesEnAttenteList.size());
                    }
                }
            } else {
                logger.warn("⚠ Dashboard ressources: réponse null de l'API");
            }
        } catch (Exception e) {
            logger.error("❌ Erreur lors du chargement du dashboard ressources", e);
        }
    }

    /**
     * Charge les métriques de maintenance depuis l'API.
     *
     * <p>Récupère :</p>
     * <ul>
     *   <li>Statistiques de maintenance (en retard, planifiées - déjà dans principal)</li>
     *   <li>Liste détaillée des maintenances en retard</li>
     * </ul>
     *
     * <p><strong>Endpoint</strong> : {@code GET /api/v1/dashboard/maintenance}</p>
     */
    private void loadDashboardMaintenance() {
        try {
            logger.debug("→ Chargement dashboard maintenance...");
            JsonNode maintenance = dashboardService.getDashboardMaintenance();

            if (maintenance != null) {
                // Maintenances en retard (détails)
                JsonNode maintenancesEnRetardNode = maintenance.get("maintenancesEnRetard");
                if (maintenancesEnRetardNode != null && maintenancesEnRetardNode.isArray()) {
                    maintenancesEnRetardList.clear();
                    Iterator<JsonNode> iterator = maintenancesEnRetardNode.elements();
                    int count = 0;

                    // Limiter à 5 maintenances pour l'affichage
                    while (iterator.hasNext() && count < 5) {
                        JsonNode maint = iterator.next();
                        MaintenanceEnRetard m = new MaintenanceEnRetard();
                        m.setId(maint.get("id").asText());
                        m.setMateriel(maint.get("materiel").asText(""));
                        m.setType(maint.get("type").asText(""));
                        m.setDescription(maint.get("description").asText(""));

                        if (maint.has("datePrevue") && !maint.get("datePrevue").isNull()) {
                            try {
                                m.setDatePrevue(LocalDate.parse(maint.get("datePrevue").asText()));
                            } catch (Exception e) {
                                logger.warn("Erreur parsing datePrevue maintenance");
                            }
                        }

                        m.setJoursRetard(maint.get("joursRetard").asLong(0));
                        maintenancesEnRetardList.add(m);
                        count++;
                    }

                    logger.debug("  ✓ {} maintenances en retard chargées (affichage limité à 5)",
                        maintenancesEnRetardList.size());
                }
            } else {
                logger.warn("⚠ Dashboard maintenance: réponse null de l'API");
            }
        } catch (Exception e) {
            logger.error("❌ Erreur lors du chargement du dashboard maintenance", e);
        }
    }

    /**
     * Charge les alertes consolidées depuis l'API.
     *
     * <p>Récupère la vue d'ensemble de toutes les alertes nécessitant une attention immédiate :</p>
     * <ul>
     *   <li>Maintenances en retard</li>
     *   <li>Chantiers en retard</li>
     *   <li>Disponibilités en attente de validation</li>
     *   <li>Conflits de planning détectés</li>
     * </ul>
     *
     * <p><strong>Endpoint</strong> : {@code GET /api/v1/dashboard/alertes}</p>
     */
    private void loadAlertes() {
        try {
            logger.debug("→ Chargement alertes...");
            JsonNode alertes = dashboardService.getAlertes();

            if (alertes != null) {
                totalAlertes = alertes.get("totalAlertes").asLong(0);
                alerteCritique = alertes.get("alerteCritique").asBoolean(false);

                // Détail par type d'alerte
                JsonNode maintenanceNode = alertes.get("maintenance");
                if (maintenanceNode != null) {
                    alertesMaintenanceCount = maintenanceNode.get("enRetard").asLong(0);
                }

                JsonNode chantiersNode = alertes.get("chantiers");
                if (chantiersNode != null) {
                    alertesChantiersCount = chantiersNode.get("enRetard").asLong(0);
                }

                JsonNode disponibilitesNode = alertes.get("disponibilites");
                if (disponibilitesNode != null) {
                    alertesDisponibilitesCount = disponibilitesNode.get("enAttente").asLong(0);
                }

                JsonNode planningNode = alertes.get("planning");
                if (planningNode != null && planningNode.has("conflits")) {
                    alertesConflitsCount = planningNode.get("conflits").asLong(0);
                    conflitsPlanningCount = alertesConflitsCount;
                }

                logger.debug("  ✓ Alertes chargées: {} total [Maintenance: {}, Chantiers: {}, Disponibilités: {}, Conflits: {}]",
                    totalAlertes, alertesMaintenanceCount, alertesChantiersCount,
                    alertesDisponibilitesCount, alertesConflitsCount);
            } else {
                logger.warn("⚠ Alertes: réponse null de l'API");
            }
        } catch (Exception e) {
            logger.error("❌ Erreur lors du chargement des alertes", e);
        }
    }

    /**
     * Rafraîchit toutes les données du dashboard.
     *
     * <p>Cette méthode peut être appelée via un bouton "Rafraîchir" ou un composant Poll
     * pour mettre à jour les données en temps réel.</p>
     */
    public void rafraichir() {
        logger.info("⟳ Rafraîchissement manuel du dashboard demandé");
        init();
    }

    /**
     * Rafraîchit uniquement les alertes.
     *
     * <p>Méthode optimisée pour le polling automatique des alertes (toutes les 30 secondes).</p>
     */
    public void refreshAlertes() {
        logger.debug("⟳ Rafraîchissement des alertes...");
        loadAlertes();
    }

    /**
     * Calcule le taux d'utilisation global moyen.
     *
     * <p>Moyenne des 3 principaux taux :</p>
     * <ul>
     *   <li>Taux d'activité des chantiers</li>
     *   <li>Taux d'activité des employés</li>
     *   <li>Taux de disponibilité du matériel</li>
     * </ul>
     *
     * @return Taux d'utilisation global en pourcentage (0-100)
     */
    public double getTauxUtilisationGlobal() {
        return (tauxActiviteChantiers + tauxActiviteEmployes + tauxDisponibiliteMateriel) / 3.0;
    }

    /**
     * Retourne l'icône PrimeIcons correspondant à un type de document.
     *
     * @param type Type de document (DEVIS, FACTURE, CONTRAT, PLAN, AUTRE)
     * @return Classe CSS de l'icône PrimeIcons
     */
    public String getIconeDocument(String type) {
        if (type == null) return "pi pi-file";

        switch (type.toUpperCase()) {
            case "DEVIS":
            case "FACTURE":
                return "pi pi-file-pdf";
            case "CONTRAT":
                return "pi pi-file-edit";
            case "PLAN":
                return "pi pi-image";
            default:
                return "pi pi-file";
        }
    }

    /**
     * Retourne la classe CSS de badge coloré selon le statut d'un chantier.
     *
     * @param statut Statut du chantier (EN_COURS, PLANIFIE, TERMINE, SUSPENDU, ANNULE)
     * @return Classe CSS du badge
     */
    public String getBadgeClasseStatut(String statut) {
        if (statut == null) return "";

        switch (statut.toUpperCase()) {
            case "EN_COURS":
                return "badge-en-cours";
            case "PLANIFIE":
                return "badge-planifie";
            case "TERMINE":
                return "badge-termine";
            case "SUSPENDU":
                return "badge-suspendu";
            case "ANNULE":
                return "badge-annule";
            default:
                return "";
        }
    }

    /**
     * Retourne la sévérité PrimeFaces d'un badge selon le type de disponibilité.
     *
     * @param type Type de disponibilité (CONGE, MALADIE, FORMATION)
     * @return Sévérité du badge (info, warning, success)
     */
    public String getSeveriteDisponibilite(String type) {
        if (type == null) return "info";

        switch (type.toUpperCase()) {
            case "CONGE":
                return "info";
            case "MALADIE":
                return "warning";
            case "FORMATION":
                return "success";
            default:
                return "info";
        }
    }

    // ============================================================================
    // CLASSES INTERNES - DTOs pour l'affichage
    // ============================================================================

    /**
     * Résumé d'un chantier actif pour affichage dans le tableau.
     */
    @lombok.Getter
    @lombok.Setter
    public static class ChantierResume implements Serializable {
        private String id;
        private String nom;
        private String adresse;
        private String client;
        private LocalDate dateDebut;
        private LocalDate dateFinPrevue;
        private String statut;
        private double budget;
        private double coutReel;
        private int avancement;

        /**
         * Retourne la date de début formatée en français.
         * @return Date au format dd/MM/yyyy
         */
        public String getDateDebutFormatee() {
            return dateDebut != null ? dateDebut.format(DATE_FORMATTER) : "";
        }

        /**
         * Retourne la date de fin prévue formatée en français.
         * @return Date au format dd/MM/yyyy
         */
        public String getDateFinPrevueFormatee() {
            return dateFinPrevue != null ? dateFinPrevue.format(DATE_FORMATTER) : "";
        }

        /**
         * Indique si le coût réel dépasse le budget.
         * @return true si dépassement de budget
         */
        public boolean isDepassementBudget() {
            return coutReel > budget;
        }
    }

    /**
     * Chantier en retard pour affichage dans la timeline.
     */
    @lombok.Getter
    @lombok.Setter
    public static class ChantierEnRetard implements Serializable {
        private String id;
        private String nom;
        private LocalDate dateFinPrevue;
        private long joursRetard;

        /**
         * Retourne la date de fin prévue formatée en français.
         * @return Date au format dd/MM/yyyy
         */
        public String getDateFinPrevueFormatee() {
            return dateFinPrevue != null ? dateFinPrevue.format(DATE_FORMATTER) : "";
        }
    }

    /**
     * Maintenance en retard pour affichage dans la liste d'alertes.
     */
    @lombok.Getter
    @lombok.Setter
    public static class MaintenanceEnRetard implements Serializable {
        private String id;
        private String materiel;
        private String type;
        private String description;
        private LocalDate datePrevue;
        private long joursRetard;

        /**
         * Retourne la date prévue formatée en français.
         * @return Date au format dd/MM/yyyy
         */
        public String getDatePrevueFormatee() {
            return datePrevue != null ? datePrevue.format(DATE_FORMATTER) : "";
        }
    }

    /**
     * Disponibilité en attente de validation.
     */
    @lombok.Getter
    @lombok.Setter
    public static class DisponibiliteEnAttente implements Serializable {
        private String id;
        private String employe;
        private String type;
        private LocalDateTime dateDebut;
        private LocalDateTime dateFin;
        private String motif;

        /**
         * Retourne la date de début formatée en français.
         * @return Date au format dd/MM/yyyy
         */
        public String getDateDebutFormatee() {
            return dateDebut != null ? dateDebut.format(DATE_FORMATTER) : "";
        }

        /**
         * Retourne la date de fin formatée en français.
         * @return Date au format dd/MM/yyyy
         */
        public String getDateFinFormatee() {
            return dateFin != null ? dateFin.format(DATE_FORMATTER) : "";
        }

        /**
         * Calcule le nombre de jours de la disponibilité.
         * @return Nombre de jours
         */
        public long getNombreJours() {
            if (dateDebut != null && dateFin != null) {
                return java.time.Duration.between(dateDebut, dateFin).toDays() + 1;
            }
            return 0;
        }
    }

    /**
     * Document récent pour affichage dans la liste.
     */
    @lombok.Getter
    @lombok.Setter
    public static class DocumentRecent implements Serializable {
        private String id;
        private String nom;
        private String type;
        private LocalDateTime dateCreation;

        /**
         * Retourne la date de création formatée en français avec heure.
         * @return Date au format dd/MM/yyyy HH:mm
         */
        public String getDateCreationFormatee() {
            return dateCreation != null ? dateCreation.format(DATETIME_FORMATTER) : "";
        }
    }
}
