package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.membre.MembreDTO;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.repository.MembreRepository;
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 org.jboss.logging.Logger;

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 les membres
 */
@ApplicationScoped
public class MembreService {

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

    @Inject
    MembreRepository membreRepository;

    /**
     * Crée un nouveau membre
     */
    @Transactional
    public Membre creerMembre(Membre membre) {
        LOG.infof("Création d'un nouveau membre: %s", membre.getEmail());
        
        // Générer un numéro de membre unique
        if (membre.getNumeroMembre() == null || membre.getNumeroMembre().isEmpty()) {
            membre.setNumeroMembre(genererNumeroMembre());
        }
        
        // Vérifier l'unicité de l'email
        if (membreRepository.findByEmail(membre.getEmail()).isPresent()) {
            throw new IllegalArgumentException("Un membre avec cet email existe déjà");
        }
        
        // Vérifier l'unicité du numéro de membre
        if (membreRepository.findByNumeroMembre(membre.getNumeroMembre()).isPresent()) {
            throw new IllegalArgumentException("Un membre avec ce numéro existe déjà");
        }
        
        membreRepository.persist(membre);
        LOG.infof("Membre créé avec succès: %s (ID: %d)", membre.getNomComplet(), membre.id);
        return membre;
    }

    /**
     * Met à jour un membre existant
     */
    @Transactional
    public Membre mettreAJourMembre(Long id, Membre membreModifie) {
        LOG.infof("Mise à jour du membre ID: %d", id);
        
        Membre membre = membreRepository.findById(id);
        if (membre == null) {
            throw new IllegalArgumentException("Membre non trouvé avec l'ID: " + id);
        }
        
        // Vérifier l'unicité de l'email si modifié
        if (!membre.getEmail().equals(membreModifie.getEmail())) {
            if (membreRepository.findByEmail(membreModifie.getEmail()).isPresent()) {
                throw new IllegalArgumentException("Un membre avec cet email existe déjà");
            }
        }
        
        // Mettre à jour les champs
        membre.setPrenom(membreModifie.getPrenom());
        membre.setNom(membreModifie.getNom());
        membre.setEmail(membreModifie.getEmail());
        membre.setTelephone(membreModifie.getTelephone());
        membre.setDateNaissance(membreModifie.getDateNaissance());
        membre.setActif(membreModifie.getActif());
        
        LOG.infof("Membre mis à jour avec succès: %s", membre.getNomComplet());
        return membre;
    }

    /**
     * Trouve un membre par son ID
     */
    public Optional<Membre> trouverParId(Long id) {
        return Optional.ofNullable(membreRepository.findById(id));
    }

    /**
     * Trouve un membre par son email
     */
    public Optional<Membre> trouverParEmail(String email) {
        return membreRepository.findByEmail(email);
    }

    /**
     * Liste tous les membres actifs
     */
    public List<Membre> listerMembresActifs() {
        return membreRepository.findAllActifs();
    }

    /**
     * Recherche des membres par nom ou prénom
     */
    public List<Membre> rechercherMembres(String recherche) {
        return membreRepository.findByNomOrPrenom(recherche);
    }

    /**
     * Désactive un membre
     */
    @Transactional
    public void desactiverMembre(Long id) {
        LOG.infof("Désactivation du membre ID: %d", id);
        
        Membre membre = membreRepository.findById(id);
        if (membre == null) {
            throw new IllegalArgumentException("Membre non trouvé avec l'ID: " + id);
        }
        
        membre.setActif(false);
        LOG.infof("Membre désactivé: %s", membre.getNomComplet());
    }

    /**
     * Génère un numéro de membre unique
     */
    private String genererNumeroMembre() {
        String prefix = "UF" + LocalDate.now().getYear();
        String suffix = UUID.randomUUID().toString().substring(0, 8).toUpperCase();
        return prefix + "-" + suffix;
    }

    /**
     * Compte le nombre total de membres actifs
     */
    public long compterMembresActifs() {
        return membreRepository.countActifs();
    }

    /**
     * Liste tous les membres actifs avec pagination
     */
    public List<Membre> listerMembresActifs(Page page, Sort sort) {
        return membreRepository.findAllActifs(page, sort);
    }

    /**
     * Recherche des membres avec pagination
     */
    public List<Membre> rechercherMembres(String recherche, Page page, Sort sort) {
        return membreRepository.findByNomOrPrenom(recherche, page, sort);
    }

    /**
     * Obtient les statistiques avancées des membres
     */
    public Map<String, Object> obtenirStatistiquesAvancees() {
        LOG.info("Calcul des statistiques avancées des membres");

        long totalMembres = membreRepository.count();
        long membresActifs = membreRepository.countActifs();
        long membresInactifs = totalMembres - membresActifs;
        long nouveauxMembres30Jours = membreRepository.countNouveauxMembres(LocalDate.now().minusDays(30));

        return Map.of(
            "totalMembres", totalMembres,
            "membresActifs", membresActifs,
            "membresInactifs", membresInactifs,
            "nouveauxMembres30Jours", nouveauxMembres30Jours,
            "tauxActivite", totalMembres > 0 ? (membresActifs * 100.0 / totalMembres) : 0.0,
            "timestamp", LocalDateTime.now()
        );
    }

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

    /**
     * Convertit une entité Membre en MembreDTO
     */
    public MembreDTO convertToDTO(Membre membre) {
        if (membre == null) {
            return null;
        }

        MembreDTO dto = new MembreDTO();

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

        // Copie des champs de base
        dto.setNumeroMembre(membre.getNumeroMembre());
        dto.setNom(membre.getNom());
        dto.setPrenom(membre.getPrenom());
        dto.setEmail(membre.getEmail());
        dto.setTelephone(membre.getTelephone());
        dto.setDateNaissance(membre.getDateNaissance());
        dto.setDateAdhesion(membre.getDateAdhesion());

        // Conversion du statut boolean vers string
        dto.setStatut(membre.getActif() ? "ACTIF" : "INACTIF");

        // Champs de base DTO
        dto.setDateCreation(membre.getDateCreation());
        dto.setDateModification(membre.getDateModification());
        dto.setVersion(0L); // Version par défaut

        // Champs par défaut pour les champs manquants dans l'entité
        dto.setAssociationId(1L); // Association par défaut
        dto.setMembreBureau(false);
        dto.setResponsable(false);

        return dto;
    }

    /**
     * Convertit un MembreDTO en entité Membre
     */
    public Membre convertFromDTO(MembreDTO dto) {
        if (dto == null) {
            return null;
        }

        Membre membre = new Membre();

        // Copie des champs
        membre.setNumeroMembre(dto.getNumeroMembre());
        membre.setNom(dto.getNom());
        membre.setPrenom(dto.getPrenom());
        membre.setEmail(dto.getEmail());
        membre.setTelephone(dto.getTelephone());
        membre.setDateNaissance(dto.getDateNaissance());
        membre.setDateAdhesion(dto.getDateAdhesion());

        // Conversion du statut string vers boolean
        membre.setActif("ACTIF".equals(dto.getStatut()));

        // Champs de base
        if (dto.getDateCreation() != null) {
            membre.setDateCreation(dto.getDateCreation());
        }
        if (dto.getDateModification() != null) {
            membre.setDateModification(dto.getDateModification());
        }

        return membre;
    }

    /**
     * Convertit une liste d'entités en liste de DTOs
     */
    public List<MembreDTO> convertToDTOList(List<Membre> membres) {
        return membres.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * Met à jour une entité Membre à partir d'un MembreDTO
     */
    public void updateFromDTO(Membre membre, MembreDTO dto) {
        if (membre == null || dto == null) {
            return;
        }

        // Mise à jour des champs modifiables
        membre.setPrenom(dto.getPrenom());
        membre.setNom(dto.getNom());
        membre.setEmail(dto.getEmail());
        membre.setTelephone(dto.getTelephone());
        membre.setDateNaissance(dto.getDateNaissance());
        membre.setActif("ACTIF".equals(dto.getStatut()));
        membre.setDateModification(LocalDateTime.now());
    }

    /**
     * Recherche avancée de membres avec filtres multiples
     */
    public List<Membre> rechercheAvancee(String recherche, Boolean actif,
                                       LocalDate dateAdhesionMin, LocalDate dateAdhesionMax,
                                       Page page, Sort sort) {
        LOG.infof("Recherche avancée - recherche: %s, actif: %s, dateMin: %s, dateMax: %s",
                 recherche, actif, dateAdhesionMin, dateAdhesionMax);

        return membreRepository.rechercheAvancee(recherche, actif, dateAdhesionMin, dateAdhesionMax, page, sort);
    }
}
