package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.suggestion.request.CreateSuggestionRequest;
import dev.lions.unionflow.server.api.dto.suggestion.response.SuggestionResponse;
import dev.lions.unionflow.server.entity.Suggestion;
import dev.lions.unionflow.server.entity.SuggestionVote;
import dev.lions.unionflow.server.repository.SuggestionRepository;
import dev.lions.unionflow.server.repository.SuggestionVoteRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.jboss.logging.Logger;

import jakarta.ws.rs.NotFoundException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Service métier pour la gestion des suggestions
 * 
 * @author UnionFlow Team
 * @version 1.0
 */
@ApplicationScoped
public class SuggestionService {

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

    @Inject
    SuggestionRepository suggestionRepository;

    @Inject
    SuggestionVoteRepository suggestionVoteRepository;

    public List<SuggestionResponse> listerSuggestions() {
        LOG.info("Récupération de toutes les suggestions");
        List<Suggestion> suggestions = suggestionRepository.findAllActivesOrderByVotes();
        return suggestions.stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    @Transactional
    public SuggestionResponse creerSuggestion(CreateSuggestionRequest request) {
        LOG.infof("Création d'une suggestion par l'utilisateur %s", request.utilisateurId());

        Suggestion suggestion = toEntity(request);
        suggestion.setDateSoumission(LocalDateTime.now());
        suggestion.setStatut("NOUVELLE");
        suggestion.setNbVotes(0);
        suggestion.setNbCommentaires(0);
        suggestion.setNbVues(0);

        suggestionRepository.persist(suggestion);
        LOG.infof("Suggestion créée avec succès: %s", suggestion.getTitre());

        return toDTO(suggestion);
    }

    @Transactional
    public void voterPourSuggestion(UUID suggestionId, UUID utilisateurId) {
        LOG.infof("Vote pour la suggestion %s par l'utilisateur %s", suggestionId, utilisateurId);

        // Vérifier que la suggestion existe
        Suggestion suggestion = suggestionRepository.findById(suggestionId);
        if (suggestion == null || !suggestion.getActif()) {
            throw new NotFoundException("Suggestion non trouvée avec l'ID: " + suggestionId);
        }

        // Vérifier que l'utilisateur n'a pas déjà voté
        if (suggestionVoteRepository.aDejaVote(suggestionId, utilisateurId)) {
            throw new IllegalStateException(
                    String.format("L'utilisateur %s a déjà voté pour la suggestion %s", utilisateurId, suggestionId));
        }

        // Créer le vote
        SuggestionVote vote = SuggestionVote.builder()
                .suggestionId(suggestionId)
                .utilisateurId(utilisateurId)
                .dateVote(LocalDateTime.now())
                .build();
        vote.setActif(true);
        suggestionVoteRepository.persist(vote);

        // Mettre à jour le compteur de votes dans la suggestion
        long nouveauNbVotes = suggestionVoteRepository.compterVotesParSuggestion(suggestionId);
        suggestion.setNbVotes((int) nouveauNbVotes);
        suggestionRepository.update(suggestion);

        LOG.infof("Vote enregistré pour la suggestion %s par l'utilisateur %s (total: %d votes)",
                suggestionId, utilisateurId, nouveauNbVotes);
    }

    public Map<String, Object> obtenirStatistiques() {
        LOG.info("Récupération des statistiques des suggestions");
        Map<String, Object> stats = new HashMap<>();
        stats.put("totalSuggestions", suggestionRepository.count());
        stats.put("suggestionsImplementees", suggestionRepository.countByStatut("IMPLEMENTEE"));
        stats.put("totalVotes", suggestionRepository.listAll().stream()
                .mapToInt(s -> s.getNbVotes() != null ? s.getNbVotes() : 0)
                .sum());
        stats.put("contributeursActifs", suggestionRepository.listAll().stream()
                .map(Suggestion::getUtilisateurId)
                .distinct()
                .count());
        return stats;
    }

    // Mappers Entity <-> DTO (DRY/WOU)
    private SuggestionResponse toDTO(Suggestion suggestion) {
        if (suggestion == null)
            return null;
        SuggestionResponse response = new SuggestionResponse();
        response.setId(suggestion.getId());
        response.setUtilisateurId(suggestion.getUtilisateurId());
        response.setUtilisateurNom(suggestion.getUtilisateurNom());
        response.setTitre(suggestion.getTitre());
        response.setDescription(suggestion.getDescription());
        response.setJustification(suggestion.getJustification());
        response.setCategorie(suggestion.getCategorie());
        response.setPrioriteEstimee(suggestion.getPrioriteEstimee());
        response.setStatut(suggestion.getStatut());
        response.setNbVotes(suggestion.getNbVotes());
        response.setNbCommentaires(suggestion.getNbCommentaires());
        response.setNbVues(suggestion.getNbVues());
        response.setDateSoumission(suggestion.getDateSoumission());
        response.setDateEvaluation(suggestion.getDateEvaluation());
        response.setDateImplementation(suggestion.getDateImplementation());
        response.setVersionCiblee(suggestion.getVersionCiblee());
        response.setMiseAJour(suggestion.getMiseAJour());
        return response;
    }

    private Suggestion toEntity(CreateSuggestionRequest dto) {
        if (dto == null)
            return null;
        Suggestion suggestion = new Suggestion();
        suggestion.setUtilisateurId(dto.utilisateurId());
        suggestion.setUtilisateurNom(dto.utilisateurNom());
        suggestion.setTitre(dto.titre());
        suggestion.setDescription(dto.description());
        suggestion.setJustification(dto.justification());
        suggestion.setCategorie(dto.categorie());
        suggestion.setPrioriteEstimee(dto.prioriteEstimee());
        suggestion.setStatut("NOUVELLE");
        suggestion.setNbVotes(0);
        suggestion.setNbCommentaires(0);
        suggestion.setNbVues(0);
        return suggestion;
    }
}
