package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Notification;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.NotificationRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import org.jboss.logging.Logger;

/**
 * Service pour gérer l'historique des notifications.
 * Persisté en base de données via NotificationRepository.
 */
@ApplicationScoped
public class NotificationHistoryService {

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

  @Inject
  NotificationRepository notificationRepository;

  @Inject
  MembreRepository membreRepository;

  /** Enregistre une notification dans l'historique (persisté en DB) */
  @Transactional
  public void enregistrerNotification(
      UUID utilisateurId, String type, String titre, String message, String canal, boolean succes) {
    LOG.infof("Enregistrement de la notification %s pour l'utilisateur %s", type, utilisateurId);

    Notification notification = new Notification();
    notification.setSujet(titre);
    notification.setCorps(message);
    notification.setDateEnvoi(LocalDateTime.now());
    notification.setDateEnvoiPrevue(LocalDateTime.now());
    notification.setNombreTentatives(1);

    // Type de notification
    notification.setTypeNotification(type != null ? type : "IN_APP");

    // Statut selon succès
    notification.setStatut(succes ? "ENVOYEE" : "ECHEC_ENVOI");
    notification.setPriorite("NORMALE");

    // Canal stocké dans données additionnelles
    notification.setDonneesAdditionnelles("{\"canal\":\"" + (canal != null ? canal : "IN_APP") + "\"}");

    // Lier au membre
    membreRepository.findByIdOptional(utilisateurId).ifPresent(notification::setMembre);

    notificationRepository.persist(notification);
  }

  /** Obtient l'historique des notifications d'un utilisateur */
  public List<Notification> obtenirHistorique(UUID utilisateurId) {
    LOG.infof("Récupération de l'historique des notifications pour l'utilisateur %s", utilisateurId);
    return notificationRepository.findByMembreId(utilisateurId);
  }

  /** Obtient l'historique des notifications d'un utilisateur avec pagination */
  public List<Notification> obtenirHistorique(UUID utilisateurId, int page, int taille) {
    return notificationRepository
        .find("membre.id = ?1 ORDER BY dateCreation DESC", utilisateurId)
        .page(page, taille)
        .list();
  }

  /** Marque une notification comme lue */
  @Transactional
  public void marquerCommeLue(UUID utilisateurId, UUID notificationId) {
    LOG.infof("Marquage de la notification %s comme lue pour l'utilisateur %s",
        notificationId, utilisateurId);

    notificationRepository.findNotificationById(notificationId).ifPresent(notification -> {
      if (notification.getMembre() != null && notification.getMembre().getId().equals(utilisateurId)) {
        notification.setStatut("LUE");
        notification.setDateLecture(LocalDateTime.now());
        notificationRepository.persist(notification);
      }
    });
  }

  /** Marque toutes les notifications comme lues */
  @Transactional
  public void marquerToutesCommeLues(UUID utilisateurId) {
    LOG.infof("Marquage de toutes les notifications comme lues pour l'utilisateur %s", utilisateurId);

    List<Notification> nonLues = notificationRepository.findNonLuesByMembreId(utilisateurId);
    LocalDateTime now = LocalDateTime.now();
    for (Notification n : nonLues) {
      n.setStatut("LUE");
      n.setDateLecture(now);
      notificationRepository.persist(n);
    }
  }

  /** Compte le nombre de notifications non lues */
  public long compterNotificationsNonLues(UUID utilisateurId) {
    return notificationRepository.count("membre.id = ?1 AND statut != ?2",
        utilisateurId, "LUE");
  }

  /** Obtient les notifications non lues */
  public List<Notification> obtenirNotificationsNonLues(UUID utilisateurId) {
    return notificationRepository.findNonLuesByMembreId(utilisateurId);
  }

  /** Supprime les notifications anciennes (plus de 90 jours) */
  @Transactional
  public void nettoyerHistorique() {
    LOG.info("Nettoyage de l'historique des notifications (> 90 jours)");
    LocalDateTime dateLimit = LocalDateTime.now().minusDays(90);
    long deleted = notificationRepository.delete("dateCreation < ?1", dateLimit);
    LOG.infof("%d notifications anciennes supprimées", deleted);
  }

  /** Obtient les statistiques des notifications pour un utilisateur */
  public Map<String, Object> obtenirStatistiques(UUID utilisateurId) {
    List<Notification> historique = obtenirHistorique(utilisateurId);

    Map<String, Object> stats = new HashMap<>();
    stats.put("total", historique.size());
    stats.put("nonLues", historique.stream()
        .filter(n -> !"LUE".equals(n.getStatut())).count());
    stats.put("succes", historique.stream()
        .filter(n -> "ENVOYEE".equals(n.getStatut()) || "LUE".equals(n.getStatut())).count());
    stats.put("echecs", historique.stream()
        .filter(n -> "ECHEC_ENVOI".equals(n.getStatut()) || "ERREUR_TECHNIQUE".equals(n.getStatut())).count());

    // Statistiques par type
    Map<String, Long> parType = historique.stream()
        .collect(Collectors.groupingBy(
            n -> n.getTypeNotification() != null ? n.getTypeNotification() : "INCONNU",
            Collectors.counting()));
    stats.put("parType", parType);

    return stats;
  }
}
