package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.solidarite.aide.AideDTO;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import dev.lions.unionflow.server.entity.Aide;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.repository.AideRepository;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import dev.lions.unionflow.server.security.KeycloakService;
import io.quarkus.panache.common.Page;
import io.quarkus.panache.common.Sort;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.NotFoundException;
import org.jboss.logging.Logger;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * Service métier pour la gestion des demandes d'aide et de solidarité
 * Implémente la logique métier complète avec validation, sécurité et gestion d'erreurs
 * 
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-15
 */
@ApplicationScoped
public class AideService {

    private static final Logger LOG = Logger.getLogger(AideService.class);

    @Inject
    AideRepository aideRepository;

    @Inject
    MembreRepository membreRepository;

    @Inject
    OrganisationRepository organisationRepository;

    @Inject
    KeycloakService keycloakService;

    // ===== OPÉRATIONS CRUD =====

    /**
     * Crée une nouvelle demande d'aide
     * 
     * @param aideDTO données de la demande d'aide
     * @return DTO de l'aide créée
     */
    @Transactional
    public AideDTO creerAide(@Valid AideDTO aideDTO) {
        LOG.infof("Création d'une nouvelle demande d'aide: %s", aideDTO.getTitre());

        // Validation du membre demandeur
        Membre membreDemandeur = membreRepository.findByIdOptional(Long.valueOf(aideDTO.getMembreDemandeurId().toString()))
                .orElseThrow(() -> new NotFoundException("Membre demandeur non trouvé avec l'ID: " + aideDTO.getMembreDemandeurId()));

        // Validation de l'organisation
        Organisation organisation = organisationRepository.findByIdOptional(Long.valueOf(aideDTO.getAssociationId().toString()))
                .orElseThrow(() -> new NotFoundException("Organisation non trouvée avec l'ID: " + aideDTO.getAssociationId()));

        // Conversion DTO vers entité
        Aide aide = convertFromDTO(aideDTO);
        aide.setMembreDemandeur(membreDemandeur);
        aide.setOrganisation(organisation);

        // Génération automatique du numéro de référence si absent
        if (aide.getNumeroReference() == null || aide.getNumeroReference().isEmpty()) {
            aide.setNumeroReference(Aide.genererNumeroReference());
        }

        // Métadonnées de création
        aide.setCreePar(keycloakService.getCurrentUserEmail());
        aide.setDateCreation(LocalDateTime.now());

        // Validation des règles métier
        validerReglesMétier(aide);

        // Persistance
        aideRepository.persist(aide);

        LOG.infof("Demande d'aide créée avec succès - ID: %d, Référence: %s", aide.id, aide.getNumeroReference());
        return convertToDTO(aide);
    }

    /**
     * Met à jour une demande d'aide existante
     * 
     * @param id identifiant de l'aide
     * @param aideDTO nouvelles données
     * @return DTO de l'aide mise à jour
     */
    @Transactional
    public AideDTO mettreAJourAide(@NotNull Long id, @Valid AideDTO aideDTO) {
        LOG.infof("Mise à jour de la demande d'aide ID: %d", id);

        Aide aide = aideRepository.findByIdOptional(id)
                .orElseThrow(() -> new NotFoundException("Demande d'aide non trouvée avec l'ID: " + id));

        // Vérifier les permissions de modification
        if (!peutModifierAide(aide)) {
            throw new SecurityException("Vous n'avez pas les permissions pour modifier cette demande d'aide");
        }

        // Vérifier si la demande peut être modifiée
        if (!aide.isPeutEtreModifiee()) {
            throw new IllegalStateException("Cette demande d'aide ne peut plus être modifiée (statut: " + aide.getStatut() + ")");
        }

        // Mise à jour des champs modifiables
        aide.setTitre(aideDTO.getTitre());
        aide.setDescription(aideDTO.getDescription());
        aide.setMontantDemande(aideDTO.getMontantDemande());
        aide.setDateLimite(aideDTO.getDateLimite());
        aide.setPriorite(aideDTO.getPriorite());
        aide.setDocumentsJoints(aideDTO.getDocumentsJoints());
        aide.setJustificatifsFournis(aideDTO.getJustificatifsFournis());

        // Métadonnées de modification
        aide.setModifiePar(keycloakService.getCurrentUserEmail());
        aide.setDateModification(LocalDateTime.now());

        // Validation des règles métier
        validerReglesMétier(aide);

        LOG.infof("Demande d'aide mise à jour avec succès: %s", aide.getNumeroReference());
        return convertToDTO(aide);
    }

    /**
     * Récupère une demande d'aide par son ID
     * 
     * @param id identifiant de l'aide
     * @return DTO de l'aide
     */
    public AideDTO obtenirAideParId(@NotNull Long id) {
        LOG.debugf("Récupération de la demande d'aide ID: %d", id);

        Aide aide = aideRepository.findByIdOptional(id)
                .orElseThrow(() -> new NotFoundException("Demande d'aide non trouvée avec l'ID: " + id));

        // Incrémenter le nombre de vues si l'aide est publique
        if (aide.getAidePublique() && !aide.getMembreDemandeur().getEmail().equals(keycloakService.getCurrentUserEmail())) {
            aide.incrementerVues();
        }

        return convertToDTO(aide);
    }

    /**
     * Récupère une demande d'aide par son numéro de référence
     * 
     * @param numeroReference numéro de référence unique
     * @return DTO de l'aide
     */
    public AideDTO obtenirAideParReference(@NotNull String numeroReference) {
        LOG.debugf("Récupération de la demande d'aide par référence: %s", numeroReference);

        Aide aide = aideRepository.findByNumeroReference(numeroReference)
                .orElseThrow(() -> new NotFoundException("Demande d'aide non trouvée avec la référence: " + numeroReference));

        // Incrémenter le nombre de vues si l'aide est publique
        if (aide.getAidePublique() && !aide.getMembreDemandeur().getEmail().equals(keycloakService.getCurrentUserEmail())) {
            aide.incrementerVues();
        }

        return convertToDTO(aide);
    }

    /**
     * Liste toutes les demandes d'aide actives avec pagination
     * 
     * @param page numéro de page
     * @param size taille de la page
     * @return liste des demandes d'aide
     */
    public List<AideDTO> listerAidesActives(int page, int size) {
        LOG.debugf("Récupération des demandes d'aide actives - page: %d, size: %d", page, size);

        List<Aide> aides = aideRepository.findAllActives();
        
        return aides.stream()
                .skip((long) page * size)
                .limit(size)
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * Liste les demandes d'aide par statut
     * 
     * @param statut statut recherché
     * @param page numéro de page
     * @param size taille de la page
     * @return liste des demandes d'aide
     */
    public List<AideDTO> listerAidesParStatut(@NotNull StatutAide statut, int page, int size) {
        LOG.debugf("Récupération des demandes d'aide par statut: %s", statut);

        List<Aide> aides = aideRepository.findByStatut(statut);
        
        return aides.stream()
                .skip((long) page * size)
                .limit(size)
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * Liste les demandes d'aide d'un membre
     * 
     * @param membreId identifiant du membre
     * @param page numéro de page
     * @param size taille de la page
     * @return liste des demandes d'aide du membre
     */
    public List<AideDTO> listerAidesParMembre(@NotNull Long membreId, int page, int size) {
        LOG.debugf("Récupération des demandes d'aide du membre: %d", membreId);

        // Vérification de l'existence du membre
        if (!membreRepository.findByIdOptional(membreId).isPresent()) {
            throw new NotFoundException("Membre non trouvé avec l'ID: " + membreId);
        }

        List<Aide> aides = aideRepository.findByMembreDemandeur(membreId);
        
        return aides.stream()
                .skip((long) page * size)
                .limit(size)
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * Liste les demandes d'aide publiques
     * 
     * @param page numéro de page
     * @param size taille de la page
     * @return liste des demandes d'aide publiques
     */
    public List<AideDTO> listerAidesPubliques(int page, int size) {
        LOG.debugf("Récupération des demandes d'aide publiques");

        List<Aide> aides = aideRepository.findAidesPubliques(
                Page.of(page, size), 
                Sort.by("dateCreation").descending()
        );
        
        return aides.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * Recherche textuelle dans les demandes d'aide
     *
     * @param recherche terme de recherche
     * @param page numéro de page
     * @param size taille de la page
     * @return liste des demandes d'aide correspondantes
     */
    public List<AideDTO> rechercherAides(@NotNull String recherche, int page, int size) {
        LOG.debugf("Recherche textuelle dans les demandes d'aide: %s", recherche);

        List<Aide> aides = aideRepository.rechercheTextuelle(
                recherche,
                Page.of(page, size),
                Sort.by("dateCreation").descending()
        );

        return aides.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    // ===== OPÉRATIONS MÉTIER SPÉCIALISÉES =====

    /**
     * Approuve une demande d'aide
     *
     * @param id identifiant de l'aide
     * @param montantApprouve montant approuvé
     * @param commentaires commentaires d'évaluation
     * @return DTO de l'aide approuvée
     */
    @Transactional
    public AideDTO approuverAide(@NotNull Long id, @NotNull BigDecimal montantApprouve, String commentaires) {
        LOG.infof("Approbation de la demande d'aide ID: %d avec montant: %s", id, montantApprouve);

        Aide aide = aideRepository.findByIdOptional(id)
                .orElseThrow(() -> new NotFoundException("Demande d'aide non trouvée avec l'ID: " + id));

        // Vérifier les permissions d'évaluation
        if (!peutEvaluerAide(aide)) {
            throw new SecurityException("Vous n'avez pas les permissions pour évaluer cette demande d'aide");
        }

        // Vérifier le statut
        if (aide.getStatut() != StatutAide.EN_ATTENTE && aide.getStatut() != StatutAide.EN_COURS_EVALUATION) {
            throw new IllegalStateException("Cette demande d'aide ne peut pas être approuvée (statut: " + aide.getStatut() + ")");
        }

        // Validation du montant approuvé
        if (montantApprouve.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("Le montant approuvé doit être positif");
        }

        if (montantApprouve.compareTo(aide.getMontantDemande()) > 0) {
            LOG.warnf("Montant approuvé (%s) supérieur au montant demandé (%s) pour l'aide %s",
                     montantApprouve, aide.getMontantDemande(), aide.getNumeroReference());
        }

        // Récupérer l'évaluateur
        String emailEvaluateur = keycloakService.getCurrentUserEmail();
        Membre evaluateur = membreRepository.findByEmail(emailEvaluateur)
                .orElseThrow(() -> new NotFoundException("Évaluateur non trouvé: " + emailEvaluateur));

        // Approuver l'aide
        aide.approuver(montantApprouve, evaluateur, commentaires);

        LOG.infof("Demande d'aide approuvée avec succès: %s", aide.getNumeroReference());
        return convertToDTO(aide);
    }

    /**
     * Rejette une demande d'aide
     *
     * @param id identifiant de l'aide
     * @param raisonRejet raison du rejet
     * @return DTO de l'aide rejetée
     */
    @Transactional
    public AideDTO rejeterAide(@NotNull Long id, @NotNull String raisonRejet) {
        LOG.infof("Rejet de la demande d'aide ID: %d", id);

        Aide aide = aideRepository.findByIdOptional(id)
                .orElseThrow(() -> new NotFoundException("Demande d'aide non trouvée avec l'ID: " + id));

        // Vérifier les permissions d'évaluation
        if (!peutEvaluerAide(aide)) {
            throw new SecurityException("Vous n'avez pas les permissions pour évaluer cette demande d'aide");
        }

        // Vérifier le statut
        if (aide.getStatut() != StatutAide.EN_ATTENTE && aide.getStatut() != StatutAide.EN_COURS_EVALUATION) {
            throw new IllegalStateException("Cette demande d'aide ne peut pas être rejetée (statut: " + aide.getStatut() + ")");
        }

        // Récupérer l'évaluateur
        String emailEvaluateur = keycloakService.getCurrentUserEmail();
        Membre evaluateur = membreRepository.findByEmail(emailEvaluateur)
                .orElseThrow(() -> new NotFoundException("Évaluateur non trouvé: " + emailEvaluateur));

        // Rejeter l'aide
        aide.rejeter(raisonRejet, evaluateur);

        LOG.infof("Demande d'aide rejetée avec succès: %s", aide.getNumeroReference());
        return convertToDTO(aide);
    }

    /**
     * Marque une aide comme versée
     *
     * @param id identifiant de l'aide
     * @param montantVerse montant effectivement versé
     * @param modeVersement mode de versement
     * @param numeroTransaction numéro de transaction
     * @return DTO de l'aide versée
     */
    @Transactional
    public AideDTO marquerCommeVersee(@NotNull Long id, @NotNull BigDecimal montantVerse,
                                     @NotNull String modeVersement, String numeroTransaction) {
        LOG.infof("Marquage comme versée de la demande d'aide ID: %d", id);

        Aide aide = aideRepository.findByIdOptional(id)
                .orElseThrow(() -> new NotFoundException("Demande d'aide non trouvée avec l'ID: " + id));

        // Vérifier les permissions
        if (!peutGererVersement(aide)) {
            throw new SecurityException("Vous n'avez pas les permissions pour gérer les versements");
        }

        // Vérifier le statut
        if (aide.getStatut() != StatutAide.APPROUVEE && aide.getStatut() != StatutAide.EN_COURS_VERSEMENT) {
            throw new IllegalStateException("Cette demande d'aide ne peut pas être marquée comme versée (statut: " + aide.getStatut() + ")");
        }

        // Validation du montant versé
        if (montantVerse.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("Le montant versé doit être positif");
        }

        if (montantVerse.compareTo(aide.getMontantApprouve()) > 0) {
            throw new IllegalArgumentException("Le montant versé ne peut pas être supérieur au montant approuvé");
        }

        // Marquer comme versée
        aide.marquerCommeVersee(montantVerse, modeVersement, numeroTransaction);

        LOG.infof("Demande d'aide marquée comme versée avec succès: %s", aide.getNumeroReference());
        return convertToDTO(aide);
    }

    /**
     * Annule une demande d'aide
     *
     * @param id identifiant de l'aide
     * @param raisonAnnulation raison de l'annulation
     * @return DTO de l'aide annulée
     */
    @Transactional
    public AideDTO annulerAide(@NotNull Long id, String raisonAnnulation) {
        LOG.infof("Annulation de la demande d'aide ID: %d", id);

        Aide aide = aideRepository.findByIdOptional(id)
                .orElseThrow(() -> new NotFoundException("Demande d'aide non trouvée avec l'ID: " + id));

        // Vérifier les permissions d'annulation
        if (!peutAnnulerAide(aide)) {
            throw new SecurityException("Vous n'avez pas les permissions pour annuler cette demande d'aide");
        }

        // Vérifier si l'aide peut être annulée
        if (aide.getStatut() == StatutAide.VERSEE) {
            throw new IllegalStateException("Une aide déjà versée ne peut pas être annulée");
        }

        // Annuler l'aide
        aide.setStatut(StatutAide.ANNULEE);
        aide.setRaisonRejet(raisonAnnulation);
        aide.setDateModification(LocalDateTime.now());
        aide.setModifiePar(keycloakService.getCurrentUserEmail());

        LOG.infof("Demande d'aide annulée avec succès: %s", aide.getNumeroReference());
        return convertToDTO(aide);
    }

    // ===== MÉTHODES DE RECHERCHE ET STATISTIQUES =====

    /**
     * Recherche avancée avec filtres multiples
     *
     * @param membreId identifiant du membre (optionnel)
     * @param organisationId identifiant de l'organisation (optionnel)
     * @param statut statut (optionnel)
     * @param typeAide type d'aide (optionnel)
     * @param priorite priorité (optionnel)
     * @param dateCreationMin date de création minimum (optionnel)
     * @param dateCreationMax date de création maximum (optionnel)
     * @param montantMin montant minimum (optionnel)
     * @param montantMax montant maximum (optionnel)
     * @param page numéro de page
     * @param size taille de la page
     * @return liste filtrée des demandes d'aide
     */
    public List<AideDTO> rechercheAvancee(Long membreId, Long organisationId, StatutAide statut,
                                        TypeAide typeAide, String priorite, LocalDate dateCreationMin,
                                        LocalDate dateCreationMax, BigDecimal montantMin,
                                        BigDecimal montantMax, int page, int size) {
        LOG.debugf("Recherche avancée de demandes d'aide avec filtres multiples");

        List<Aide> aides = aideRepository.rechercheAvancee(
                membreId, organisationId, statut, typeAide, priorite,
                dateCreationMin, dateCreationMax, montantMin, montantMax,
                Page.of(page, size), Sort.by("dateCreation").descending()
        );

        return aides.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * Obtient les statistiques globales des demandes d'aide
     *
     * @return map contenant les statistiques
     */
    public Map<String, Object> obtenirStatistiquesGlobales() {
        LOG.debug("Récupération des statistiques globales des demandes d'aide");
        return aideRepository.getStatistiquesGlobales();
    }

    /**
     * Obtient les statistiques pour une période donnée
     *
     * @param dateDebut date de début
     * @param dateFin date de fin
     * @return map contenant les statistiques de la période
     */
    public Map<String, Object> obtenirStatistiquesPeriode(@NotNull LocalDate dateDebut, @NotNull LocalDate dateFin) {
        LOG.debugf("Récupération des statistiques pour la période: %s - %s", dateDebut, dateFin);

        if (dateDebut.isAfter(dateFin)) {
            throw new IllegalArgumentException("La date de début doit être antérieure à la date de fin");
        }

        return aideRepository.getStatistiquesPeriode(dateDebut, dateFin);
    }

    /**
     * Liste les demandes d'aide urgentes en attente
     *
     * @return liste des demandes d'aide urgentes
     */
    public List<AideDTO> listerAidesUrgentesEnAttente() {
        LOG.debug("Récupération des demandes d'aide urgentes en attente");

        List<Aide> aides = aideRepository.findAidesUrgentesEnAttente();

        return aides.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * Liste les demandes d'aide nécessitant un suivi
     *
     * @param joursDepuisApprobation nombre de jours depuis l'approbation
     * @return liste des demandes d'aide nécessitant un suivi
     */
    public List<AideDTO> listerAidesNecessitantSuivi(int joursDepuisApprobation) {
        LOG.debugf("Récupération des demandes d'aide nécessitant un suivi (%d jours)", joursDepuisApprobation);

        List<Aide> aides = aideRepository.findAidesNecessitantSuivi(joursDepuisApprobation);

        return aides.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * Liste les demandes d'aide les plus consultées
     *
     * @param limite nombre maximum d'aides à retourner
     * @return liste des demandes d'aide les plus consultées
     */
    public List<AideDTO> listerAidesLesPlusConsultees(int limite) {
        LOG.debugf("Récupération des %d demandes d'aide les plus consultées", limite);

        List<Aide> aides = aideRepository.findAidesLesPlusConsultees(limite);

        return aides.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * Liste les demandes d'aide récentes
     *
     * @param nombreJours nombre de jours
     * @param page numéro de page
     * @param size taille de la page
     * @return liste des demandes d'aide récentes
     */
    public List<AideDTO> listerAidesRecentes(int nombreJours, int page, int size) {
        LOG.debugf("Récupération des demandes d'aide récentes (%d jours)", nombreJours);

        List<Aide> aides = aideRepository.findAidesRecentes(
                nombreJours,
                Page.of(page, size),
                Sort.by("dateCreation").descending()
        );

        return aides.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    // ===== MÉTHODES DE VALIDATION ET SÉCURITÉ =====

    /**
     * Valide les règles métier pour une demande d'aide
     *
     * @param aide l'aide à valider
     */
    private void validerReglesMétier(Aide aide) {
        // Validation du montant demandé
        if (aide.getMontantDemande() != null && aide.getMontantDemande().compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("Le montant demandé doit être positif");
        }

        // Validation de la date limite
        if (aide.getDateLimite() != null && aide.getDateLimite().isBefore(LocalDate.now())) {
            throw new IllegalArgumentException("La date limite ne peut pas être dans le passé");
        }

        // Validation du type d'aide et du montant
        if (aide.getTypeAide() == TypeAide.AIDE_FINANCIERE_URGENTE && aide.getMontantDemande() == null) {
            throw new IllegalArgumentException("Le montant demandé est obligatoire pour une aide financière");
        }

        // Validation des justificatifs pour certains types d'aide
        if ((aide.getTypeAide() == TypeAide.AIDE_FRAIS_MEDICAUX || aide.getTypeAide() == TypeAide.CONSEIL_JURIDIQUE)
            && !aide.getJustificatifsFournis()) {
            LOG.warnf("Justificatifs recommandés pour le type d'aide: %s", aide.getTypeAide());
        }
    }

    /**
     * Vérifie si l'utilisateur actuel peut modifier une demande d'aide
     *
     * @param aide l'aide à vérifier
     * @return true si l'utilisateur peut modifier l'aide
     */
    private boolean peutModifierAide(Aide aide) {
        String emailUtilisateur = keycloakService.getCurrentUserEmail();

        // Le demandeur peut modifier sa propre demande
        if (aide.getMembreDemandeur().getEmail().equals(emailUtilisateur)) {
            return true;
        }

        // Les administrateurs peuvent modifier toutes les demandes
        return keycloakService.hasRole("admin") || keycloakService.hasRole("gestionnaire_aide");
    }

    /**
     * Vérifie si l'utilisateur actuel peut évaluer une demande d'aide
     *
     * @param aide l'aide à vérifier
     * @return true si l'utilisateur peut évaluer l'aide
     */
    private boolean peutEvaluerAide(Aide aide) {
        String emailUtilisateur = keycloakService.getCurrentUserEmail();

        // Le demandeur ne peut pas évaluer sa propre demande
        if (aide.getMembreDemandeur().getEmail().equals(emailUtilisateur)) {
            return false;
        }

        // Seuls les évaluateurs autorisés peuvent évaluer
        return keycloakService.hasRole("admin") ||
               keycloakService.hasRole("evaluateur_aide") ||
               keycloakService.hasRole("gestionnaire_aide");
    }

    /**
     * Vérifie si l'utilisateur actuel peut gérer les versements
     *
     * @param aide l'aide à vérifier
     * @return true si l'utilisateur peut gérer les versements
     */
    private boolean peutGererVersement(Aide aide) {
        return keycloakService.hasRole("admin") ||
               keycloakService.hasRole("tresorier") ||
               keycloakService.hasRole("gestionnaire_aide");
    }

    /**
     * Vérifie si l'utilisateur actuel peut annuler une demande d'aide
     *
     * @param aide l'aide à vérifier
     * @return true si l'utilisateur peut annuler l'aide
     */
    private boolean peutAnnulerAide(Aide aide) {
        String emailUtilisateur = keycloakService.getCurrentUserEmail();

        // Le demandeur peut annuler sa propre demande si elle n'est pas encore approuvée
        if (aide.getMembreDemandeur().getEmail().equals(emailUtilisateur) &&
            aide.getStatut() == StatutAide.EN_ATTENTE) {
            return true;
        }

        // Les administrateurs peuvent annuler toutes les demandes
        return keycloakService.hasRole("admin") || keycloakService.hasRole("gestionnaire_aide");
    }

    // ===== MÉTHODES DE CONVERSION DTO/ENTITY =====

    /**
     * Convertit une entité Aide en DTO
     *
     * @param aide l'entité à convertir
     * @return le DTO correspondant
     */
    public AideDTO convertToDTO(Aide aide) {
        if (aide == null) {
            return null;
        }

        AideDTO dto = new AideDTO();

        // Génération d'UUID basé sur l'ID numérique pour compatibilité
        dto.setId(UUID.nameUUIDFromBytes(("aide-" + aide.id).getBytes()));

        // Copie des champs de base
        dto.setNumeroReference(aide.getNumeroReference());
        dto.setTitre(aide.getTitre());
        dto.setDescription(aide.getDescription());
        dto.setMontantDemande(aide.getMontantDemande());
        dto.setMontantApprouve(aide.getMontantApprouve());
        dto.setMontantVerse(aide.getMontantVerse());
        dto.setDevise(aide.getDevise());
        dto.setPriorite(aide.getPriorite());
        dto.setDateLimite(aide.getDateLimite());
        dto.setDateDebutAide(aide.getDateDebutAide());
        dto.setDateFinAide(aide.getDateFinAide());
        dto.setJustificatifsFournis(aide.getJustificatifsFournis());
        dto.setDocumentsJoints(aide.getDocumentsJoints());
        dto.setCommentairesEvaluateur(aide.getCommentairesEvaluateur());
        dto.setDateEvaluation(aide.getDateEvaluation());
        dto.setModeVersement(aide.getModeVersement());
        dto.setNumeroTransaction(aide.getNumeroTransaction());
        dto.setDateVersement(aide.getDateVersement());
        dto.setCommentairesBeneficiaire(aide.getCommentairesBeneficiaire());
        dto.setNoteSatisfaction(aide.getNoteSatisfaction());
        dto.setAidePublique(aide.getAidePublique());
        dto.setAideAnonyme(aide.getAideAnonyme());
        dto.setNombreVues(aide.getNombreVues());
        dto.setRaisonRejet(aide.getRaisonRejet());
        dto.setDateRejet(aide.getDateRejet());

        // Conversion des énumérations vers String
        if (aide.getStatut() != null) {
            dto.setStatut(aide.getStatut().name());
        }
        if (aide.getTypeAide() != null) {
            dto.setTypeAide(aide.getTypeAide().name());
        }

        // Informations du membre demandeur
        if (aide.getMembreDemandeur() != null) {
            dto.setMembreDemandeurId(UUID.nameUUIDFromBytes(("membre-" + aide.getMembreDemandeur().id).getBytes()));
            dto.setNomDemandeur(aide.getNomDemandeur());
            dto.setNumeroMembreDemandeur(aide.getMembreDemandeur().getNumeroMembre());
        }

        // Informations de l'organisation
        if (aide.getOrganisation() != null) {
            dto.setAssociationId(UUID.nameUUIDFromBytes(("organisation-" + aide.getOrganisation().id).getBytes()));
            dto.setNomAssociation(aide.getOrganisation().getNom());
        }

        // Informations de l'évaluateur (pas de champs spécifiques dans AideDTO)
        // Les informations d'évaluation sont dans dateEvaluation et commentairesEvaluateur

        // Informations de rejet
        if (aide.getRejetePar() != null) {
            dto.setRejeteParId(UUID.nameUUIDFromBytes(("membre-" + aide.getRejetePar().id).getBytes()));
            dto.setRejetePar(aide.getRejetePar().getNomComplet());
        }

        // Champs d'audit (hérités de BaseDTO)
        dto.setActif(aide.getActif());
        dto.setDateCreation(aide.getDateCreation());
        dto.setDateModification(aide.getDateModification());
        // Les champs creePar, modifiePar et version sont gérés par BaseDTO

        return dto;
    }

    /**
     * Convertit un DTO en entité Aide
     *
     * @param dto le DTO à convertir
     * @return l'entité correspondante
     */
    public Aide convertFromDTO(AideDTO dto) {
        if (dto == null) {
            return null;
        }

        Aide aide = new Aide();

        // Copie des champs de base
        aide.setNumeroReference(dto.getNumeroReference());
        aide.setTitre(dto.getTitre());
        aide.setDescription(dto.getDescription());
        aide.setMontantDemande(dto.getMontantDemande());
        aide.setMontantApprouve(dto.getMontantApprouve());
        aide.setMontantVerse(dto.getMontantVerse());
        aide.setDevise(dto.getDevise());
        aide.setPriorite(dto.getPriorite());
        aide.setDateLimite(dto.getDateLimite());
        aide.setDateDebutAide(dto.getDateDebutAide());
        aide.setDateFinAide(dto.getDateFinAide());
        aide.setJustificatifsFournis(dto.getJustificatifsFournis());
        aide.setDocumentsJoints(dto.getDocumentsJoints());
        aide.setCommentairesEvaluateur(dto.getCommentairesEvaluateur());
        aide.setDateEvaluation(dto.getDateEvaluation());
        aide.setModeVersement(dto.getModeVersement());
        aide.setNumeroTransaction(dto.getNumeroTransaction());
        aide.setDateVersement(dto.getDateVersement());
        aide.setCommentairesBeneficiaire(dto.getCommentairesBeneficiaire());
        aide.setNoteSatisfaction(dto.getNoteSatisfaction());
        aide.setAidePublique(dto.getAidePublique());
        aide.setAideAnonyme(dto.getAideAnonyme());
        aide.setNombreVues(dto.getNombreVues());
        aide.setRaisonRejet(dto.getRaisonRejet());
        aide.setDateRejet(dto.getDateRejet());

        // Champs d'audit
        aide.setActif(dto.isActif());
        aide.setDateCreation(dto.getDateCreation());
        aide.setDateModification(dto.getDateModification());

        // Conversion des énumérations depuis String
        if (dto.getStatut() != null && !dto.getStatut().isEmpty()) {
            try {
                aide.setStatut(StatutAide.valueOf(dto.getStatut()));
            } catch (IllegalArgumentException e) {
                LOG.warnf("Statut invalide: %s, utilisation de EN_ATTENTE par défaut", dto.getStatut());
                aide.setStatut(StatutAide.EN_ATTENTE);
            }
        }

        if (dto.getTypeAide() != null && !dto.getTypeAide().isEmpty()) {
            try {
                // Conversion du String vers l'énumération TypeAide
                String typeAideStr = dto.getTypeAide();
                // Mapping des valeurs du DTO vers l'énumération
                TypeAide typeAide = switch (typeAideStr) {
                    case "FINANCIERE" -> TypeAide.AIDE_FINANCIERE_URGENTE;
                    case "MATERIELLE" -> TypeAide.DON_MATERIEL;
                    case "MEDICALE" -> TypeAide.AIDE_FRAIS_MEDICAUX;
                    case "JURIDIQUE" -> TypeAide.CONSEIL_JURIDIQUE;
                    case "LOGEMENT" -> TypeAide.HEBERGEMENT_URGENCE;
                    case "EDUCATION" -> TypeAide.AIDE_FRAIS_SCOLARITE;
                    case "AUTRE" -> TypeAide.AUTRE;
                    default -> {
                        LOG.warnf("Type d'aide non mappé: %s, utilisation de AUTRE", typeAideStr);
                        yield TypeAide.AUTRE;
                    }
                };
                aide.setTypeAide(typeAide);
            } catch (Exception e) {
                LOG.warnf("Erreur lors de la conversion du type d'aide: %s", dto.getTypeAide());
                aide.setTypeAide(TypeAide.AUTRE);
            }
        }

        return aide;
    }

    /**
     * Convertit une liste d'entités en liste de DTOs
     *
     * @param aides liste des entités
     * @return liste des DTOs
     */
    public List<AideDTO> convertToDTOList(List<Aide> aides) {
        if (aides == null) {
            return null;
        }

        return aides.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }
}
