package dev.lions.utils;

import lombok.extern.slf4j.Slf4j;
import jakarta.enterprise.context.ApplicationScoped;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Collecteur de métriques pour le suivi des performances et des événements de l'application.
 * Cette classe fournit des méthodes thread-safe pour collecter et suivre différentes métriques.
 *
 * @author Lions Dev Team
 * @version 1.0
 */
@Slf4j
@ApplicationScoped
public class MetricsCollector {

  /**
   * Map thread-safe stockant les compteurs d'événements par type
   */
  private final Map<String, AtomicLong> counters = new ConcurrentHashMap<>();

  /**
   * Map stockant les valeurs des métriques générales
   */
  private final Map<String, AtomicLong> metrics = new ConcurrentHashMap<>();

  /**
   * Collecte une métrique avec une valeur spécifique.
   *
   * @param metricName Nom de la métrique
   * @param value Valeur à enregistrer
   */
  public void collect(String metricName, long value) {
    log.debug("Collecte de la métrique '{}' avec la valeur {}", metricName, value);
    metrics.computeIfAbsent(metricName, k -> new AtomicLong(0))
           .set(value);
  }

  /**
   * Incrémente le compteur pour un type d'événement spécifique.
   *
   * @param eventType Type d'événement à incrémenter
   */
  public void incrementEventCounter(String eventType) {
    log.trace("Incrémentation du compteur pour l'événement de type '{}'", eventType);
    long newValue = counters.computeIfAbsent(eventType, k -> new AtomicLong(0))
                            .incrementAndGet();
    log.debug("Nouveau compteur pour '{}' : {}", eventType, newValue);
  }

  /**
   * Récupère le nombre d'occurrences d'un type d'événement.
   *
   * @param eventType Type d'événement
   * @return Nombre d'occurrences
   */
  public long getEventCount(String eventType) {
    return counters.getOrDefault(eventType, new AtomicLong(0)).get();
  }

  /**
   * Récupère la valeur actuelle d'une métrique.
   *
   * @param metricName Nom de la métrique
   * @return Valeur actuelle
   */
  public long getMetricValue(String metricName) {
    return metrics.getOrDefault(metricName, new AtomicLong(0)).get();
  }

  /**
   * Réinitialise le compteur pour un type d'événement spécifique.
   *
   * @param eventType Type d'événement à réinitialiser
   */
  public void resetEventCounter(String eventType) {
    log.debug("Réinitialisation du compteur pour l'événement '{}'", eventType);
    counters.put(eventType, new AtomicLong(0));
  }

  /**
   * Réinitialise tous les compteurs d'événements.
   */
  public void resetAllCounters() {
    log.info("Réinitialisation de tous les compteurs d'événements");
    counters.clear();
  }

  /**
   * Récupère un snapshot de tous les compteurs d'événements.
   *
   * @return Map des compteurs actuels
   */
  public Map<String, Long> getEventCountersSnapshot() {
    Map<String, Long> snapshot = new ConcurrentHashMap<>();
    counters.forEach((key, value) -> snapshot.put(key, value.get()));
    return snapshot;
  }
}