package dev.lions.unionflow.server.service;

import jakarta.enterprise.context.ApplicationScoped;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.jboss.logging.Logger;

/** Service pour gérer l'historique des notifications */
@ApplicationScoped
public class NotificationHistoryService {

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

  // Stockage temporaire en mémoire (à remplacer par une base de données)
  private final Map<UUID, List<NotificationHistoryEntry>> historiqueNotifications =
      new ConcurrentHashMap<>();

  /** Enregistre une notification dans l'historique */
  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);

    NotificationHistoryEntry entry =
        NotificationHistoryEntry.builder()
            .id(UUID.randomUUID())
            .utilisateurId(utilisateurId)
            .type(type)
            .titre(titre)
            .message(message)
            .canal(canal)
            .dateEnvoi(LocalDateTime.now())
            .succes(succes)
            .lu(false)
            .build();

    historiqueNotifications.computeIfAbsent(utilisateurId, k -> new ArrayList<>()).add(entry);

    // Limiter l'historique à 1000 notifications par utilisateur
    List<NotificationHistoryEntry> historique = historiqueNotifications.get(utilisateurId);
    if (historique.size() > 1000) {
      historique.sort(Comparator.comparing(NotificationHistoryEntry::getDateEnvoi).reversed());
      historiqueNotifications.put(utilisateurId, historique.subList(0, 1000));
    }
  }

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

    return historiqueNotifications.getOrDefault(utilisateurId, new ArrayList<>()).stream()
        .sorted(Comparator.comparing(NotificationHistoryEntry::getDateEnvoi).reversed())
        .collect(Collectors.toList());
  }

  /** Obtient l'historique des notifications d'un utilisateur avec pagination */
  public List<NotificationHistoryEntry> obtenirHistorique(
      UUID utilisateurId, int page, int taille) {
    List<NotificationHistoryEntry> historique = obtenirHistorique(utilisateurId);

    int debut = page * taille;
    int fin = Math.min(debut + taille, historique.size());

    if (debut >= historique.size()) {
      return new ArrayList<>();
    }

    return historique.subList(debut, fin);
  }

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

    List<NotificationHistoryEntry> historique = historiqueNotifications.get(utilisateurId);
    if (historique != null) {
      historique.stream()
          .filter(entry -> entry.getId().equals(notificationId))
          .findFirst()
          .ifPresent(entry -> entry.setLu(true));
    }
  }

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

    List<NotificationHistoryEntry> historique = historiqueNotifications.get(utilisateurId);
    if (historique != null) {
      historique.forEach(entry -> entry.setLu(true));
    }
  }

  /** Compte le nombre de notifications non lues */
  public long compterNotificationsNonLues(UUID utilisateurId) {
    return obtenirHistorique(utilisateurId).stream().filter(entry -> !entry.isLu()).count();
  }

  /** Obtient les notifications non lues */
  public List<NotificationHistoryEntry> obtenirNotificationsNonLues(UUID utilisateurId) {
    return obtenirHistorique(utilisateurId).stream()
        .filter(entry -> !entry.isLu())
        .collect(Collectors.toList());
  }

  /** Supprime les notifications anciennes (plus de 90 jours) */
  public void nettoyerHistorique() {
    LOG.info("Nettoyage de l'historique des notifications");

    LocalDateTime dateLimit = LocalDateTime.now().minusDays(90);

    for (Map.Entry<UUID, List<NotificationHistoryEntry>> entry :
        historiqueNotifications.entrySet()) {
      List<NotificationHistoryEntry> historique = entry.getValue();
      List<NotificationHistoryEntry> historiqueFiltre =
          historique.stream()
              .filter(notification -> notification.getDateEnvoi().isAfter(dateLimit))
              .collect(Collectors.toList());

      entry.setValue(historiqueFiltre);
    }
  }

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

    Map<String, Object> stats = new HashMap<>();
    stats.put("total", historique.size());
    stats.put("nonLues", historique.stream().filter(entry -> !entry.isLu()).count());
    stats.put("succes", historique.stream().filter(NotificationHistoryEntry::isSucces).count());
    stats.put("echecs", historique.stream().filter(entry -> !entry.isSucces()).count());

    // Statistiques par type
    Map<String, Long> parType =
        historique.stream()
            .collect(
                Collectors.groupingBy(NotificationHistoryEntry::getType, Collectors.counting()));
    stats.put("parType", parType);

    // Statistiques par canal
    Map<String, Long> parCanal =
        historique.stream()
            .collect(
                Collectors.groupingBy(NotificationHistoryEntry::getCanal, Collectors.counting()));
    stats.put("parCanal", parCanal);

    return stats;
  }

  /** Classe interne pour représenter une entrée d'historique */
  public static class NotificationHistoryEntry {
    private UUID id;
    private UUID utilisateurId;
    private String type;
    private String titre;
    private String message;
    private String canal;
    private LocalDateTime dateEnvoi;
    private boolean succes;
    private boolean lu;

    // Constructeurs
    public NotificationHistoryEntry() {}

    private NotificationHistoryEntry(Builder builder) {
      this.id = builder.id;
      this.utilisateurId = builder.utilisateurId;
      this.type = builder.type;
      this.titre = builder.titre;
      this.message = builder.message;
      this.canal = builder.canal;
      this.dateEnvoi = builder.dateEnvoi;
      this.succes = builder.succes;
      this.lu = builder.lu;
    }

    public static Builder builder() {
      return new Builder();
    }

    // Getters et Setters
    public UUID getId() {
      return id;
    }

    public void setId(UUID id) {
      this.id = id;
    }

    public UUID getUtilisateurId() {
      return utilisateurId;
    }

    public void setUtilisateurId(UUID utilisateurId) {
      this.utilisateurId = utilisateurId;
    }

    public String getType() {
      return type;
    }

    public void setType(String type) {
      this.type = type;
    }

    public String getTitre() {
      return titre;
    }

    public void setTitre(String titre) {
      this.titre = titre;
    }

    public String getMessage() {
      return message;
    }

    public void setMessage(String message) {
      this.message = message;
    }

    public String getCanal() {
      return canal;
    }

    public void setCanal(String canal) {
      this.canal = canal;
    }

    public LocalDateTime getDateEnvoi() {
      return dateEnvoi;
    }

    public void setDateEnvoi(LocalDateTime dateEnvoi) {
      this.dateEnvoi = dateEnvoi;
    }

    public boolean isSucces() {
      return succes;
    }

    public void setSucces(boolean succes) {
      this.succes = succes;
    }

    public boolean isLu() {
      return lu;
    }

    public void setLu(boolean lu) {
      this.lu = lu;
    }

    // Builder
    public static class Builder {
      private UUID id;
      private UUID utilisateurId;
      private String type;
      private String titre;
      private String message;
      private String canal;
      private LocalDateTime dateEnvoi;
      private boolean succes;
      private boolean lu;

      public Builder id(UUID id) {
        this.id = id;
        return this;
      }

      public Builder utilisateurId(UUID utilisateurId) {
        this.utilisateurId = utilisateurId;
        return this;
      }

      public Builder type(String type) {
        this.type = type;
        return this;
      }

      public Builder titre(String titre) {
        this.titre = titre;
        return this;
      }

      public Builder message(String message) {
        this.message = message;
        return this;
      }

      public Builder canal(String canal) {
        this.canal = canal;
        return this;
      }

      public Builder dateEnvoi(LocalDateTime dateEnvoi) {
        this.dateEnvoi = dateEnvoi;
        return this;
      }

      public Builder succes(boolean succes) {
        this.succes = succes;
        return this;
      }

      public Builder lu(boolean lu) {
        this.lu = lu;
        return this;
      }

      public NotificationHistoryEntry build() {
        return new NotificationHistoryEntry(this);
      }
    }
  }
}
