package dev.lions.events;

import dev.lions.exceptions.EventPublicationException;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Event;
import jakarta.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Implémentation du publisher d'événements analytiques utilisant le système
 * d'événements CDI de Quarkus pour le traitement asynchrone.
 *
 * @author Lions Dev Team
 * @version 1.1
 */
@Slf4j
@ApplicationScoped
public class QuarkusAnalyticsEventPublisher implements AnalyticsEventPublisher {

  @Inject
  Event<AnalyticsEvent> eventBus;

  /**
   * Publie un événement analytique de manière asynchrone.
   *
   * @param event L'événement à publier
   * @throws EventPublicationException Si la publication échoue
   */
  @Override
  public void publish(AnalyticsEvent event) {
    log.debug("Publication d'un événement analytique de type: {}", event.getEventType());

    try {
      eventBus.fireAsync(event)
              .handle((success, error) -> {
                if (error != null) {
                  log.error("Erreur lors de la publication de l'événement analytique: {}",
                            error.getMessage(), error);
                  throw new EventPublicationException(
                      "Échec de la publication de l'événement analytique", error);
                } else {
                  log.debug("Événement analytique publié avec succès: {}",
                            event.getEventType());
                }
                return null;
              });
    } catch (Exception e) {
      log.error("Erreur inattendue lors de la publication de l'événement", e);
      throw new EventPublicationException(
          "Échec de la publication de l'événement analytique", e);
    }
  }

  /**
   * Publie un lot d'événements analytiques.
   *
   * @param events Collection d'événements à publier
   * @throws EventPublicationException Si la publication d'un des événements échoue
   */
  @Override
  public void publishBatch(Iterable<AnalyticsEvent> events) {
    log.debug("Début de la publication du lot d'événements");
    AtomicInteger count = new AtomicInteger(0);

    try {
      events.forEach(event -> {
        publish(event);
        count.incrementAndGet();
      });

      log.info("Lot de {} événements publié avec succès", count.get());
    } catch (Exception e) {
      log.error("Erreur lors de la publication du lot après {} événements", count.get(), e);
      throw new EventPublicationException(
          String.format("Échec de la publication du lot après %d événements", count.get()),
          e);
    }
  }
}