package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.notification.NotificationDTO;
import dev.lions.unionflow.server.api.dto.notification.ActionNotificationDTO;
import dev.lions.unionflow.server.api.enums.notification.TypeNotification;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Service de gestion des templates de notifications
 * 
 * Ce service applique des templates dynamiques aux notifications
 * en fonction du type, du contexte et des données personnalisées.
 * 
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-16
 */
@ApplicationScoped
public class NotificationTemplateService {
    
    private static final Logger LOG = Logger.getLogger(NotificationTemplateService.class);
    
    // Pattern pour détecter les variables dans les templates
    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{\\{([^}]+)\\}\\}");
    
    // Formatters pour les dates
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");
    private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy à HH:mm");
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
    
    @Inject
    MembreService membreService;
    
    @Inject
    OrganisationService organisationService;
    
    @Inject
    EvenementService evenementService;
    
    // Cache des templates pour optimiser les performances
    private final Map<TypeNotification, NotificationTemplate> templatesCache = new HashMap<>();
    
    /**
     * Applique un template à une notification
     * 
     * @param notification La notification à traiter
     * @return La notification avec le template appliqué
     */
    public NotificationDTO appliquerTemplate(NotificationDTO notification) {
        LOG.debugf("Application du template pour: %s", notification.getTypeNotification());
        
        try {
            // Récupération du template
            NotificationTemplate template = obtenirTemplate(notification.getTypeNotification());
            
            if (template == null) {
                LOG.warnf("Aucun template trouvé pour: %s", notification.getTypeNotification());
                return notification;
            }
            
            // Préparation des variables de contexte
            Map<String, Object> contexte = construireContexte(notification);
            
            // Application du template au titre
            if (template.getTitreTemplate() != null) {
                String titrePersonnalise = appliquerVariables(template.getTitreTemplate(), contexte);
                notification.setTitre(titrePersonnalise);
            }
            
            // Application du template au message
            if (template.getMessageTemplate() != null) {
                String messagePersonnalise = appliquerVariables(template.getMessageTemplate(), contexte);
                notification.setMessage(messagePersonnalise);
            }
            
            // Application du template au message court
            if (template.getMessageCourtTemplate() != null) {
                String messageCourtPersonnalise = appliquerVariables(template.getMessageCourtTemplate(), contexte);
                notification.setMessageCourt(messageCourtPersonnalise);
            }
            
            // Application des actions rapides du template
            if (template.getActionsRapides() != null && !template.getActionsRapides().isEmpty()) {
                List<ActionNotificationDTO> actionsPersonnalisees = new ArrayList<>();
                
                for (ActionNotificationDTO actionTemplate : template.getActionsRapides()) {
                    ActionNotificationDTO actionPersonnalisee = new ActionNotificationDTO();
                    actionPersonnalisee.setId(actionTemplate.getId());
                    actionPersonnalisee.setTypeAction(actionTemplate.getTypeAction());
                    actionPersonnalisee.setLibelle(appliquerVariables(actionTemplate.getLibelle(), contexte));
                    actionPersonnalisee.setDescription(appliquerVariables(actionTemplate.getDescription(), contexte));
                    actionPersonnalisee.setIcone(actionTemplate.getIcone());
                    actionPersonnalisee.setCouleur(actionTemplate.getCouleur());
                    actionPersonnalisee.setRoute(appliquerVariables(actionTemplate.getRoute(), contexte));
                    actionPersonnalisee.setUrl(appliquerVariables(actionTemplate.getUrl(), contexte));
                    
                    // Paramètres personnalisés
                    if (actionTemplate.getParametres() != null) {
                        Map<String, String> parametresPersonnalises = new HashMap<>();
                        actionTemplate.getParametres().forEach((key, value) -> 
                            parametresPersonnalises.put(key, appliquerVariables(value, contexte)));
                        actionPersonnalisee.setParametres(parametresPersonnalises);
                    }
                    
                    actionsPersonnalisees.add(actionPersonnalisee);
                }
                
                notification.setActionsRapides(actionsPersonnalisees);
            }
            
            // Application des propriétés du template
            if (template.getImageUrl() != null) {
                notification.setImageUrl(appliquerVariables(template.getImageUrl(), contexte));
            }
            
            if (template.getIconeUrl() != null) {
                notification.setIconeUrl(appliquerVariables(template.getIconeUrl(), contexte));
            }
            
            if (template.getActionClic() != null) {
                notification.setActionClic(appliquerVariables(template.getActionClic(), contexte));
            }
            
            // Fusion des données personnalisées
            if (template.getDonneesPersonnalisees() != null) {
                Map<String, Object> donneesPersonnalisees = notification.getDonneesPersonnalisees();
                if (donneesPersonnalisees == null) {
                    donneesPersonnalisees = new HashMap<>();
                    notification.setDonneesPersonnalisees(donneesPersonnalisees);
                }
                
                template.getDonneesPersonnalisees().forEach((key, value) -> {
                    String valeurPersonnalisee = appliquerVariables(String.valueOf(value), contexte);
                    donneesPersonnalisees.put(key, valeurPersonnalisee);
                });
            }
            
            LOG.debugf("Template appliqué avec succès pour: %s", notification.getTypeNotification());
            return notification;
            
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors de l'application du template pour: %s", notification.getTypeNotification());
            return notification; // Retourner la notification originale en cas d'erreur
        }
    }
    
    /**
     * Crée une notification à partir d'un template
     * 
     * @param typeNotification Type de notification
     * @param destinatairesIds Liste des destinataires
     * @param donneesContexte Données de contexte pour le template
     * @return La notification créée
     */
    public NotificationDTO creerDepuisTemplate(
            TypeNotification typeNotification,
            List<String> destinatairesIds,
            Map<String, Object> donneesContexte) {
        
        LOG.debugf("Création de notification depuis template: %s", typeNotification);
        
        // Création de la notification de base
        NotificationDTO notification = new NotificationDTO();
        notification.setId(UUID.randomUUID().toString());
        notification.setTypeNotification(typeNotification);
        notification.setDestinatairesIds(destinatairesIds);
        notification.setDonneesPersonnalisees(donneesContexte);
        
        // Application du template
        return appliquerTemplate(notification);
    }
    
    // === MÉTHODES PRIVÉES ===
    
    /**
     * Obtient le template pour un type de notification
     */
    private NotificationTemplate obtenirTemplate(TypeNotification type) {
        return templatesCache.computeIfAbsent(type, this::chargerTemplate);
    }
    
    /**
     * Charge un template depuis la configuration
     */
    private NotificationTemplate chargerTemplate(TypeNotification type) {
        // Dans un vrai projet, les templates seraient stockés en base de données
        // ou dans des fichiers de configuration. Ici, nous les définissons en dur.
        
        return switch (type) {
            case NOUVEL_EVENEMENT -> creerTemplateNouvelEvenement();
            case RAPPEL_EVENEMENT -> creerTemplateRappelEvenement();
            case COTISATION_DUE -> creerTemplateCotisationDue();
            case COTISATION_PAYEE -> creerTemplateCotisationPayee();
            case NOUVELLE_DEMANDE_AIDE -> creerTemplateNouvelleDemandeAide();
            case NOUVEAU_MEMBRE -> creerTemplateNouveauMembre();
            case ANNIVERSAIRE_MEMBRE -> creerTemplateAnniversaireMembre();
            case ANNONCE_GENERALE -> creerTemplateAnnonceGenerale();
            case MESSAGE_PRIVE -> creerTemplateMessagePrive();
            default -> creerTemplateDefaut(type);
        };
    }
    
    /**
     * Construit le contexte de variables pour le template
     */
    private Map<String, Object> construireContexte(NotificationDTO notification) {
        Map<String, Object> contexte = new HashMap<>();
        
        // Variables de base
        contexte.put("notification_id", notification.getId());
        contexte.put("type", notification.getTypeNotification().getLibelle());
        contexte.put("date_creation", DATE_FORMATTER.format(notification.getDateCreation()));
        contexte.put("datetime_creation", DATETIME_FORMATTER.format(notification.getDateCreation()));
        contexte.put("heure_creation", TIME_FORMATTER.format(notification.getDateCreation()));
        
        // Variables de l'expéditeur
        if (notification.getExpediteurId() != null) {
            try {
                // Récupération des informations de l'expéditeur
                var expediteur = membreService.obtenirMembre(notification.getExpediteurId());
                if (expediteur != null) {
                    contexte.put("expediteur_nom", expediteur.getNom());
                    contexte.put("expediteur_prenom", expediteur.getPrenom());
                    contexte.put("expediteur_nom_complet", expediteur.getNom() + " " + expediteur.getPrenom());
                }
            } catch (Exception e) {
                LOG.warnf("Impossible de récupérer les infos de l'expéditeur: %s", notification.getExpediteurId());
            }
        }
        
        // Variables de l'organisation
        if (notification.getOrganisationId() != null) {
            try {
                var organisation = organisationService.obtenirOrganisation(notification.getOrganisationId());
                if (organisation != null) {
                    contexte.put("organisation_nom", organisation.getNom());
                    contexte.put("organisation_ville", organisation.getVille());
                }
            } catch (Exception e) {
                LOG.warnf("Impossible de récupérer les infos de l'organisation: %s", notification.getOrganisationId());
            }
        }
        
        // Variables des données personnalisées
        if (notification.getDonneesPersonnalisees() != null) {
            notification.getDonneesPersonnalisees().forEach((key, value) -> {
                contexte.put(key, value);
                
                // Formatage spécial pour les dates
                if (value instanceof LocalDateTime) {
                    LocalDateTime dateTime = (LocalDateTime) value;
                    contexte.put(key + "_date", DATE_FORMATTER.format(dateTime));
                    contexte.put(key + "_datetime", DATETIME_FORMATTER.format(dateTime));
                    contexte.put(key + "_heure", TIME_FORMATTER.format(dateTime));
                }
            });
        }
        
        // Variables calculées
        contexte.put("nombre_destinataires", notification.getDestinatairesIds().size());
        contexte.put("est_groupe", notification.getDestinatairesIds().size() > 1);
        
        return contexte;
    }
    
    /**
     * Applique les variables à un template de texte
     */
    private String appliquerVariables(String template, Map<String, Object> contexte) {
        if (template == null) return null;
        
        Matcher matcher = VARIABLE_PATTERN.matcher(template);
        StringBuffer result = new StringBuffer();
        
        while (matcher.find()) {
            String variableName = matcher.group(1).trim();
            Object value = contexte.get(variableName);
            
            String replacement;
            if (value != null) {
                replacement = String.valueOf(value);
            } else {
                // Variable non trouvée, on garde la variable originale
                replacement = "{{" + variableName + "}}";
                LOG.warnf("Variable non trouvée dans le contexte: %s", variableName);
            }
            
            matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
        }
        matcher.appendTail(result);
        
        return result.toString();
    }
    
    // === TEMPLATES PRÉDÉFINIS ===
    
    private NotificationTemplate creerTemplateNouvelEvenement() {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate("Nouvel événement : {{evenement_titre}}");
        template.setMessageTemplate("Un nouvel événement \"{{evenement_titre}}\" a été créé pour le {{evenement_date}}. Inscrivez-vous dès maintenant !");
        template.setMessageCourtTemplate("Nouvel événement le {{evenement_date}}");
        template.setImageUrl("{{evenement_image_url}}");
        template.setActionClic("/evenements/{{evenement_id}}");
        
        // Actions rapides
        List<ActionNotificationDTO> actions = Arrays.asList(
            new ActionNotificationDTO("voir", "Voir", "/evenements/{{evenement_id}}", "visibility"),
            new ActionNotificationDTO("inscrire", "S'inscrire", "/evenements/{{evenement_id}}/inscription", "event_available")
        );
        template.setActionsRapides(actions);
        
        return template;
    }
    
    private NotificationTemplate creerTemplateRappelEvenement() {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate("Rappel : {{evenement_titre}}");
        template.setMessageTemplate("N'oubliez pas l'événement \"{{evenement_titre}}\" qui aura lieu {{evenement_date}} à {{evenement_heure}}.");
        template.setMessageCourtTemplate("Événement dans {{temps_restant}}");
        template.setActionClic("/evenements/{{evenement_id}}");
        
        List<ActionNotificationDTO> actions = Arrays.asList(
            new ActionNotificationDTO("voir", "Voir", "/evenements/{{evenement_id}}", "visibility"),
            new ActionNotificationDTO("itineraire", "Itinéraire", "geo:{{evenement_latitude}},{{evenement_longitude}}", "directions")
        );
        template.setActionsRapides(actions);
        
        return template;
    }
    
    private NotificationTemplate creerTemplateCotisationDue() {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate("Cotisation due");
        template.setMessageTemplate("Votre cotisation de {{montant}} FCFA est due. Échéance : {{date_echeance}}");
        template.setMessageCourtTemplate("Cotisation {{montant}} FCFA due");
        template.setActionClic("/cotisations/payer/{{cotisation_id}}");
        
        List<ActionNotificationDTO> actions = Arrays.asList(
            new ActionNotificationDTO("payer", "Payer maintenant", "/cotisations/payer/{{cotisation_id}}", "payment"),
            new ActionNotificationDTO("reporter", "Reporter", "/cotisations/reporter/{{cotisation_id}}", "schedule")
        );
        template.setActionsRapides(actions);
        
        return template;
    }
    
    private NotificationTemplate creerTemplateCotisationPayee() {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate("Cotisation payée ✓");
        template.setMessageTemplate("Votre cotisation de {{montant}} FCFA a été payée avec succès. Merci !");
        template.setMessageCourtTemplate("Paiement {{montant}} FCFA confirmé");
        template.setActionClic("/cotisations/recu/{{cotisation_id}}");
        
        List<ActionNotificationDTO> actions = Arrays.asList(
            new ActionNotificationDTO("recu", "Voir le reçu", "/cotisations/recu/{{cotisation_id}}", "receipt")
        );
        template.setActionsRapides(actions);
        
        return template;
    }
    
    private NotificationTemplate creerTemplateNouvelleDemandeAide() {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate("Nouvelle demande d'aide");
        template.setMessageTemplate("{{demandeur_nom}} a fait une demande d'aide : {{demande_titre}}");
        template.setMessageCourtTemplate("Demande d'aide de {{demandeur_nom}}");
        template.setActionClic("/solidarite/demandes/{{demande_id}}");
        
        List<ActionNotificationDTO> actions = Arrays.asList(
            new ActionNotificationDTO("voir", "Voir", "/solidarite/demandes/{{demande_id}}", "visibility"),
            new ActionNotificationDTO("aider", "Proposer aide", "/solidarite/demandes/{{demande_id}}/aider", "volunteer_activism")
        );
        template.setActionsRapides(actions);
        
        return template;
    }
    
    private NotificationTemplate creerTemplateNouveauMembre() {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate("Nouveau membre");
        template.setMessageTemplate("{{membre_nom}} {{membre_prenom}} a rejoint notre organisation. Souhaitons-lui la bienvenue !");
        template.setMessageCourtTemplate("{{membre_nom}} a rejoint l'organisation");
        template.setActionClic("/membres/{{membre_id}}");
        
        List<ActionNotificationDTO> actions = Arrays.asList(
            new ActionNotificationDTO("voir", "Voir profil", "/membres/{{membre_id}}", "person"),
            new ActionNotificationDTO("message", "Envoyer message", "/messages/nouveau/{{membre_id}}", "message")
        );
        template.setActionsRapides(actions);
        
        return template;
    }
    
    private NotificationTemplate creerTemplateAnniversaireMembre() {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate("Joyeux anniversaire ! 🎉");
        template.setMessageTemplate("C'est l'anniversaire de {{membre_nom}} {{membre_prenom}} aujourd'hui ! Souhaitons-lui un joyeux anniversaire.");
        template.setMessageCourtTemplate("Anniversaire de {{membre_nom}}");
        template.setActionClic("/membres/{{membre_id}}");
        
        List<ActionNotificationDTO> actions = Arrays.asList(
            new ActionNotificationDTO("feliciter", "Féliciter", "/membres/{{membre_id}}/feliciter", "cake"),
            new ActionNotificationDTO("appeler", "Appeler", "tel:{{membre_telephone}}", "phone")
        );
        template.setActionsRapides(actions);
        
        return template;
    }
    
    private NotificationTemplate creerTemplateAnnonceGenerale() {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate("{{annonce_titre}}");
        template.setMessageTemplate("{{annonce_contenu}}");
        template.setMessageCourtTemplate("Nouvelle annonce");
        template.setActionClic("/annonces/{{annonce_id}}");
        
        return template;
    }
    
    private NotificationTemplate creerTemplateMessagePrive() {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate("Message de {{expediteur_nom}}");
        template.setMessageTemplate("{{message_contenu}}");
        template.setMessageCourtTemplate("Nouveau message privé");
        template.setActionClic("/messages/{{message_id}}");
        
        List<ActionNotificationDTO> actions = Arrays.asList(
            new ActionNotificationDTO("repondre", "Répondre", "/messages/repondre/{{message_id}}", "reply"),
            new ActionNotificationDTO("voir", "Voir", "/messages/{{message_id}}", "visibility")
        );
        template.setActionsRapides(actions);
        
        return template;
    }
    
    private NotificationTemplate creerTemplateDefaut(TypeNotification type) {
        NotificationTemplate template = new NotificationTemplate();
        template.setTitreTemplate(type.getLibelle());
        template.setMessageTemplate("{{message}}");
        template.setMessageCourtTemplate("{{message_court}}");
        
        return template;
    }
    
    // === CLASSE INTERNE POUR LES TEMPLATES ===
    
    private static class NotificationTemplate {
        private String titreTemplate;
        private String messageTemplate;
        private String messageCourtTemplate;
        private String imageUrl;
        private String iconeUrl;
        private String actionClic;
        private List<ActionNotificationDTO> actionsRapides;
        private Map<String, Object> donneesPersonnalisees;
        
        // Getters et setters
        public String getTitreTemplate() { return titreTemplate; }
        public void setTitreTemplate(String titreTemplate) { this.titreTemplate = titreTemplate; }
        
        public String getMessageTemplate() { return messageTemplate; }
        public void setMessageTemplate(String messageTemplate) { this.messageTemplate = messageTemplate; }
        
        public String getMessageCourtTemplate() { return messageCourtTemplate; }
        public void setMessageCourtTemplate(String messageCourtTemplate) { this.messageCourtTemplate = messageCourtTemplate; }
        
        public String getImageUrl() { return imageUrl; }
        public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
        
        public String getIconeUrl() { return iconeUrl; }
        public void setIconeUrl(String iconeUrl) { this.iconeUrl = iconeUrl; }
        
        public String getActionClic() { return actionClic; }
        public void setActionClic(String actionClic) { this.actionClic = actionClic; }
        
        public List<ActionNotificationDTO> getActionsRapides() { return actionsRapides; }
        public void setActionsRapides(List<ActionNotificationDTO> actionsRapides) { this.actionsRapides = actionsRapides; }
        
        public Map<String, Object> getDonneesPersonnalisees() { return donneesPersonnalisees; }
        public void setDonneesPersonnalisees(Map<String, Object> donneesPersonnalisees) { 
            this.donneesPersonnalisees = donneesPersonnalisees; 
        }
    }
}
