package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.solidarite.DemandeAideDTO;
import dev.lions.unionflow.server.api.dto.solidarite.PropositionAideDTO;
import dev.lions.unionflow.server.api.dto.solidarite.EvaluationAideDTO;
import dev.lions.unionflow.server.api.dto.notification.NotificationDTO;
import dev.lions.unionflow.server.api.enums.notification.TypeNotification;
import dev.lions.unionflow.server.api.enums.notification.CanalNotification;
import dev.lions.unionflow.server.api.enums.solidarite.PrioriteAide;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * Service spécialisé pour les notifications du système de solidarité
 * 
 * Ce service gère toutes les notifications liées aux demandes d'aide,
 * propositions, évaluations et processus de solidarité.
 * 
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-16
 */
@ApplicationScoped
public class NotificationSolidariteService {
    
    private static final Logger LOG = Logger.getLogger(NotificationSolidariteService.class);
    
    @Inject
    NotificationService notificationService;
    
    @ConfigProperty(name = "unionflow.solidarite.notifications.enabled", defaultValue = "true")
    boolean notificationsEnabled;
    
    @ConfigProperty(name = "unionflow.solidarite.notifications.urgence.immediate", defaultValue = "true")
    boolean notificationsUrgenceImmediate;
    
    // === NOTIFICATIONS DEMANDES D'AIDE ===
    
    /**
     * Notifie la création d'une nouvelle demande d'aide
     * 
     * @param demande La demande d'aide créée
     */
    public CompletableFuture<Void> notifierCreationDemande(DemandeAideDTO demande) {
        if (!notificationsEnabled) return CompletableFuture.completedFuture(null);
        
        LOG.infof("Notification de création de demande: %s", demande.getId());
        
        return CompletableFuture.runAsync(() -> {
            try {
                // Notification au demandeur
                NotificationDTO notificationDemandeur = creerNotificationBase(
                    TypeNotification.DEMANDE_AIDE_CREEE,
                    "Demande d'aide créée",
                    String.format("Votre demande d'aide \"%s\" a été créée avec succès.", demande.getTitre()),
                    List.of(demande.getDemandeurId())
                );
                
                ajouterDonneesContexteDemande(notificationDemandeur, demande);
                notificationService.envoyerNotification(notificationDemandeur);
                
                // Notification aux administrateurs si priorité élevée
                if (demande.getPriorite().getNiveau() <= 2) {
                    notifierAdministrateursNouvelleDemandeUrgente(demande);
                }
                
            } catch (Exception e) {
                LOG.errorf(e, "Erreur lors de la notification de création de demande: %s", demande.getId());
            }
        });
    }
    
    /**
     * Notifie la soumission d'une demande d'aide
     * 
     * @param demande La demande soumise
     */
    public CompletableFuture<Void> notifierSoumissionDemande(DemandeAideDTO demande) {
        if (!notificationsEnabled) return CompletableFuture.completedFuture(null);
        
        LOG.infof("Notification de soumission de demande: %s", demande.getId());
        
        return CompletableFuture.runAsync(() -> {
            try {
                // Notification au demandeur
                NotificationDTO notification = creerNotificationBase(
                    TypeNotification.DEMANDE_AIDE_SOUMISE,
                    "Demande d'aide soumise",
                    String.format("Votre demande \"%s\" a été soumise et sera évaluée dans les %d heures.", 
                                 demande.getTitre(), demande.getPriorite().getDelaiTraitementHeures()),
                    List.of(demande.getDemandeurId())
                );
                
                ajouterDonneesContexteDemande(notification, demande);
                notificationService.envoyerNotification(notification);
                
            } catch (Exception e) {
                LOG.errorf(e, "Erreur lors de la notification de soumission: %s", demande.getId());
            }
        });
    }
    
    /**
     * Notifie une décision d'évaluation
     * 
     * @param demande La demande évaluée
     */
    public CompletableFuture<Void> notifierDecisionEvaluation(DemandeAideDTO demande) {
        if (!notificationsEnabled) return CompletableFuture.completedFuture(null);
        
        LOG.infof("Notification de décision d'évaluation: %s", demande.getId());
        
        return CompletableFuture.runAsync(() -> {
            try {
                TypeNotification typeNotification;
                String titre;
                String message;
                
                switch (demande.getStatut()) {
                    case APPROUVEE -> {
                        typeNotification = TypeNotification.DEMANDE_AIDE_APPROUVEE;
                        titre = "Demande d'aide approuvée";
                        message = String.format("Excellente nouvelle ! Votre demande \"%s\" a été approuvée.", 
                                               demande.getTitre());
                        if (demande.getMontantApprouve() != null) {
                            message += String.format(" Montant approuvé : %.0f FCFA", demande.getMontantApprouve());
                        }
                    }
                    case APPROUVEE_PARTIELLEMENT -> {
                        typeNotification = TypeNotification.DEMANDE_AIDE_APPROUVEE;
                        titre = "Demande d'aide partiellement approuvée";
                        message = String.format("Votre demande \"%s\" a été partiellement approuvée. Montant : %.0f FCFA", 
                                               demande.getTitre(), demande.getMontantApprouve());
                    }
                    case REJETEE -> {
                        typeNotification = TypeNotification.DEMANDE_AIDE_REJETEE;
                        titre = "Demande d'aide rejetée";
                        message = String.format("Votre demande \"%s\" n'a pas pu être approuvée.", demande.getTitre());
                        if (demande.getMotifRejet() != null) {
                            message += " Motif : " + demande.getMotifRejet();
                        }
                    }
                    case INFORMATIONS_REQUISES -> {
                        typeNotification = TypeNotification.INFORMATIONS_REQUISES;
                        titre = "Informations complémentaires requises";
                        message = String.format("Des informations complémentaires sont nécessaires pour votre demande \"%s\".", 
                                               demande.getTitre());
                    }
                    default -> {
                        return; // Pas de notification pour les autres statuts
                    }
                }
                
                NotificationDTO notification = creerNotificationBase(
                    typeNotification, titre, message, List.of(demande.getDemandeurId())
                );
                
                ajouterDonneesContexteDemande(notification, demande);
                notificationService.envoyerNotification(notification);
                
            } catch (Exception e) {
                LOG.errorf(e, "Erreur lors de la notification de décision: %s", demande.getId());
            }
        });
    }
    
    /**
     * Notifie une urgence critique
     * 
     * @param demande La demande critique
     */
    public CompletableFuture<Void> notifierUrgenceCritique(DemandeAideDTO demande) {
        if (!notificationsEnabled || !notificationsUrgenceImmediate) {
            return CompletableFuture.completedFuture(null);
        }
        
        LOG.warnf("Notification d'urgence critique pour la demande: %s", demande.getId());
        
        return CompletableFuture.runAsync(() -> {
            try {
                // Notification immédiate aux administrateurs et évaluateurs
                List<String> destinataires = obtenirAdministrateursEtEvaluateurs(demande.getOrganisationId());
                
                NotificationDTO notification = creerNotificationBase(
                    TypeNotification.URGENCE_CRITIQUE,
                    "🚨 URGENCE CRITIQUE - Demande d'aide",
                    String.format("ATTENTION : Demande d'aide critique \"%s\" nécessitant une intervention immédiate.", 
                                 demande.getTitre()),
                    destinataires
                );
                
                // Canal prioritaire pour les urgences
                notification.setCanalNotification(CanalNotification.URGENCE);
                notification.setPriorite(1); // Priorité maximale
                
                ajouterDonneesContexteDemande(notification, demande);
                notificationService.envoyerNotification(notification);
                
                // Notification SMS/appel si configuré
                if (demande.getContactUrgence() != null) {
                    notifierContactUrgence(demande);
                }
                
            } catch (Exception e) {
                LOG.errorf(e, "Erreur lors de la notification d'urgence critique: %s", demande.getId());
            }
        });
    }
    
    // === NOTIFICATIONS PROPOSITIONS D'AIDE ===
    
    /**
     * Notifie la création d'une proposition d'aide
     * 
     * @param proposition La proposition créée
     */
    public CompletableFuture<Void> notifierCreationProposition(PropositionAideDTO proposition) {
        if (!notificationsEnabled) return CompletableFuture.completedFuture(null);
        
        LOG.infof("Notification de création de proposition: %s", proposition.getId());
        
        return CompletableFuture.runAsync(() -> {
            try {
                NotificationDTO notification = creerNotificationBase(
                    TypeNotification.PROPOSITION_AIDE_CREEE,
                    "Proposition d'aide créée",
                    String.format("Votre proposition d'aide \"%s\" a été créée et est maintenant active.", 
                                 proposition.getTitre()),
                    List.of(proposition.getProposantId())
                );
                
                ajouterDonneesContexteProposition(notification, proposition);
                notificationService.envoyerNotification(notification);
                
            } catch (Exception e) {
                LOG.errorf(e, "Erreur lors de la notification de création de proposition: %s", 
                          proposition.getId());
            }
        });
    }
    
    /**
     * Notifie les proposants compatibles d'une nouvelle demande
     * 
     * @param demande La nouvelle demande
     * @param propositionsCompatibles Les propositions compatibles
     */
    public CompletableFuture<Void> notifierProposantsCompatibles(DemandeAideDTO demande, 
                                                                List<PropositionAideDTO> propositionsCompatibles) {
        if (!notificationsEnabled || propositionsCompatibles.isEmpty()) {
            return CompletableFuture.completedFuture(null);
        }
        
        LOG.infof("Notification de %d proposants compatibles pour la demande: %s", 
                 propositionsCompatibles.size(), demande.getId());
        
        return CompletableFuture.runAsync(() -> {
            try {
                List<String> proposantsIds = propositionsCompatibles.stream()
                        .map(PropositionAideDTO::getProposantId)
                        .distinct()
                        .toList();
                
                NotificationDTO notification = creerNotificationBase(
                    TypeNotification.DEMANDE_COMPATIBLE_TROUVEE,
                    "Nouvelle demande d'aide compatible",
                    String.format("Une nouvelle demande d'aide \"%s\" correspond à votre proposition.", 
                                 demande.getTitre()),
                    proposantsIds
                );
                
                ajouterDonneesContexteDemande(notification, demande);
                
                // Ajout du score de compatibilité
                Map<String, Object> donneesSupplementaires = new HashMap<>();
                donneesSupplementaires.put("nombrePropositionsCompatibles", propositionsCompatibles.size());
                donneesSupplementaires.put("typeAide", demande.getTypeAide().getLibelle());
                notification.getDonneesPersonnalisees().putAll(donneesSupplementaires);
                
                notificationService.envoyerNotification(notification);
                
            } catch (Exception e) {
                LOG.errorf(e, "Erreur lors de la notification aux proposants compatibles");
            }
        });
    }
    
    /**
     * Notifie un proposant de demandes compatibles
     * 
     * @param proposition La proposition
     * @param demandesCompatibles Les demandes compatibles
     */
    public CompletableFuture<Void> notifierDemandesCompatibles(PropositionAideDTO proposition, 
                                                              List<DemandeAideDTO> demandesCompatibles) {
        if (!notificationsEnabled || demandesCompatibles.isEmpty()) {
            return CompletableFuture.completedFuture(null);
        }
        
        LOG.infof("Notification de %d demandes compatibles pour la proposition: %s", 
                 demandesCompatibles.size(), proposition.getId());
        
        return CompletableFuture.runAsync(() -> {
            try {
                String message = demandesCompatibles.size() == 1 ?
                    String.format("Une demande d'aide \"%s\" correspond à votre proposition.", 
                                 demandesCompatibles.get(0).getTitre()) :
                    String.format("%d demandes d'aide correspondent à votre proposition \"%s\".", 
                                 demandesCompatibles.size(), proposition.getTitre());
                
                NotificationDTO notification = creerNotificationBase(
                    TypeNotification.PROPOSITIONS_COMPATIBLES_TROUVEES,
                    "Demandes d'aide compatibles trouvées",
                    message,
                    List.of(proposition.getProposantId())
                );
                
                ajouterDonneesContexteProposition(notification, proposition);
                
                // Ajout des détails des demandes
                Map<String, Object> donneesSupplementaires = new HashMap<>();
                donneesSupplementaires.put("nombreDemandesCompatibles", demandesCompatibles.size());
                donneesSupplementaires.put("demandesUrgentes", 
                    demandesCompatibles.stream().filter(DemandeAideDTO::isUrgente).count());
                notification.getDonneesPersonnalisees().putAll(donneesSupplementaires);
                
                notificationService.envoyerNotification(notification);
                
            } catch (Exception e) {
                LOG.errorf(e, "Erreur lors de la notification des demandes compatibles");
            }
        });
    }
    
    // === NOTIFICATIONS ÉVALUATEURS ===
    
    /**
     * Notifie les évaluateurs d'une nouvelle demande à évaluer
     * 
     * @param demande La demande à évaluer
     */
    public CompletableFuture<Void> notifierEvaluateurs(DemandeAideDTO demande) {
        if (!notificationsEnabled) return CompletableFuture.completedFuture(null);
        
        LOG.infof("Notification aux évaluateurs pour la demande: %s", demande.getId());
        
        return CompletableFuture.runAsync(() -> {
            try {
                List<String> evaluateurs = obtenirEvaluateursDisponibles(demande.getOrganisationId());
                
                if (!evaluateurs.isEmpty()) {
                    String prioriteTexte = demande.getPriorite().isUrgente() ? " URGENTE" : "";
                    
                    NotificationDTO notification = creerNotificationBase(
                        TypeNotification.DEMANDE_A_EVALUER,
                        "Nouvelle demande d'aide à évaluer" + prioriteTexte,
                        String.format("Une nouvelle demande d'aide%s \"%s\" nécessite votre évaluation.", 
                                     prioriteTexte.toLowerCase(), demande.getTitre()),
                        evaluateurs
                    );
                    
                    if (demande.getPriorite().isUrgente()) {
                        notification.setCanalNotification(CanalNotification.URGENT);
                        notification.setPriorite(2);
                    }
                    
                    ajouterDonneesContexteDemande(notification, demande);
                    notificationService.envoyerNotification(notification);
                }
                
            } catch (Exception e) {
                LOG.errorf(e, "Erreur lors de la notification aux évaluateurs: %s", demande.getId());
            }
        });
    }
    
    // === RAPPELS ET PROGRAMMATION ===
    
    /**
     * Programme les rappels automatiques pour une demande
     * 
     * @param demande La demande
     * @param rappel50 Rappel à 50% du délai
     * @param rappel80 Rappel à 80% du délai
     * @param rappelDepassement Rappel de dépassement
     */
    public void programmerRappels(DemandeAideDTO demande, 
                                 LocalDateTime rappel50, 
                                 LocalDateTime rappel80, 
                                 LocalDateTime rappelDepassement) {
        if (!notificationsEnabled) return;
        
        LOG.infof("Programmation des rappels pour la demande: %s", demande.getId());
        
        try {
            // Rappel à 50%
            NotificationDTO notification50 = creerNotificationRappel(demande, 
                "Rappel : 50% du délai écoulé", 
                "La moitié du délai de traitement est écoulée.");
            notificationService.programmerNotification(notification50, rappel50);
            
            // Rappel à 80%
            NotificationDTO notification80 = creerNotificationRappel(demande, 
                "Rappel urgent : 80% du délai écoulé", 
                "Attention : 80% du délai de traitement est écoulé !");
            notification80.setCanalNotification(CanalNotification.URGENT);
            notificationService.programmerNotification(notification80, rappel80);
            
            // Rappel de dépassement
            NotificationDTO notificationDepassement = creerNotificationRappel(demande, 
                "🚨 DÉLAI DÉPASSÉ", 
                "ATTENTION : Le délai de traitement est dépassé !");
            notificationDepassement.setCanalNotification(CanalNotification.URGENCE);
            notificationDepassement.setPriorite(1);
            notificationService.programmerNotification(notificationDepassement, rappelDepassement);
            
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la programmation des rappels pour: %s", demande.getId());
        }
    }
    
    /**
     * Programme un rappel pour informations requises
     * 
     * @param demande La demande nécessitant des informations
     * @param dateRappel Date du rappel
     */
    public void programmerRappelInformationsRequises(DemandeAideDTO demande, LocalDateTime dateRappel) {
        if (!notificationsEnabled) return;
        
        LOG.infof("Programmation du rappel d'informations pour la demande: %s", demande.getId());
        
        try {
            NotificationDTO notification = creerNotificationBase(
                TypeNotification.RAPPEL_INFORMATIONS_REQUISES,
                "Rappel : Informations complémentaires requises",
                String.format("N'oubliez pas de fournir les informations complémentaires pour votre demande \"%s\".", 
                             demande.getTitre()),
                List.of(demande.getDemandeurId())
            );
            
            ajouterDonneesContexteDemande(notification, demande);
            notificationService.programmerNotification(notification, dateRappel);
            
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de la programmation du rappel d'informations: %s", demande.getId());
        }
    }
    
    // === MÉTHODES UTILITAIRES PRIVÉES ===
    
    /**
     * Crée une notification de base
     */
    private NotificationDTO creerNotificationBase(TypeNotification type, String titre, 
                                                 String message, List<String> destinataires) {
        return NotificationDTO.builder()
                .id(UUID.randomUUID().toString())
                .typeNotification(type)
                .titre(titre)
                .message(message)
                .destinatairesIds(destinataires)
                .canalNotification(CanalNotification.GENERAL)
                .priorite(3)
                .donneesPersonnalisees(new HashMap<>())
                .dateCreation(LocalDateTime.now())
                .build();
    }
    
    /**
     * Ajoute les données de contexte d'une demande à une notification
     */
    private void ajouterDonneesContexteDemande(NotificationDTO notification, DemandeAideDTO demande) {
        Map<String, Object> donnees = notification.getDonneesPersonnalisees();
        donnees.put("demandeId", demande.getId());
        donnees.put("numeroReference", demande.getNumeroReference());
        donnees.put("typeAide", demande.getTypeAide().getLibelle());
        donnees.put("priorite", demande.getPriorite().getLibelle());
        donnees.put("statut", demande.getStatut().getLibelle());
        if (demande.getMontantDemande() != null) {
            donnees.put("montant", demande.getMontantDemande());
        }
    }
    
    /**
     * Ajoute les données de contexte d'une proposition à une notification
     */
    private void ajouterDonneesContexteProposition(NotificationDTO notification, PropositionAideDTO proposition) {
        Map<String, Object> donnees = notification.getDonneesPersonnalisees();
        donnees.put("propositionId", proposition.getId());
        donnees.put("numeroReference", proposition.getNumeroReference());
        donnees.put("typeAide", proposition.getTypeAide().getLibelle());
        donnees.put("statut", proposition.getStatut().getLibelle());
        if (proposition.getMontantMaximum() != null) {
            donnees.put("montantMaximum", proposition.getMontantMaximum());
        }
    }
    
    /**
     * Crée une notification de rappel
     */
    private NotificationDTO creerNotificationRappel(DemandeAideDTO demande, String titre, String messageRappel) {
        List<String> destinataires = obtenirEvaluateursAssignes(demande);
        
        String message = String.format("%s Demande : \"%s\" (%s)", 
                                      messageRappel, demande.getTitre(), demande.getNumeroReference());
        
        NotificationDTO notification = creerNotificationBase(
            TypeNotification.RAPPEL_DELAI_TRAITEMENT,
            titre,
            message,
            destinataires
        );
        
        ajouterDonneesContexteDemande(notification, demande);
        return notification;
    }
    
    // === MÉTHODES DE SIMULATION (À REMPLACER PAR DE VRAIS SERVICES) ===
    
    private List<String> obtenirAdministrateursEtEvaluateurs(String organisationId) {
        // Simulation - dans une vraie implémentation, ceci ferait appel au service utilisateur
        return List.of("admin1", "evaluateur1", "evaluateur2");
    }
    
    private List<String> obtenirEvaluateursDisponibles(String organisationId) {
        // Simulation
        return List.of("evaluateur1", "evaluateur2", "evaluateur3");
    }
    
    private List<String> obtenirEvaluateursAssignes(DemandeAideDTO demande) {
        // Simulation
        return demande.getEvaluateurId() != null ? 
               List.of(demande.getEvaluateurId()) : 
               obtenirEvaluateursDisponibles(demande.getOrganisationId());
    }
    
    private void notifierAdministrateursNouvelleDemandeUrgente(DemandeAideDTO demande) {
        // Simulation d'une notification spéciale aux administrateurs
        LOG.infof("Notification spéciale aux administrateurs pour demande urgente: %s", demande.getId());
    }
    
    private void notifierContactUrgence(DemandeAideDTO demande) {
        // Simulation d'une notification au contact d'urgence
        LOG.infof("Notification au contact d'urgence pour la demande: %s", demande.getId());
    }
}
