package com.airlock.iam.common.infrastructure.event;

import com.airlock.iam.base.api.domain.model.event.DomainEvent;
import com.airlock.iam.base.domain.model.event.EventPublisher;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.domain.service.event.EventOrderingTiebreaker;
import com.airlock.iam.common.domain.service.event.EventOutboxRepository;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import jakarta.inject.Provider;
import java.util.function.Predicate;

public final class OutboxEventPublisher implements EventPublisher {
   private static final ELogger LOG = ELoggerFactory.getLogger(OutboxEventPublisher.class);
   private final Provider<EventOutboxRepository> eventOutboxRepository;
   private final Provider<OutboxEventSerializer> outboxEventSerializer;
   private final Provider<EventOrderingTiebreaker> tiebreaker;
   private final Predicate<DomainEvent> skipEvent;

   public OutboxEventPublisher(
      Provider<EventOutboxRepository> eventOutboxRepository,
      Provider<OutboxEventSerializer> outboxEventSerializer,
      Provider<EventOrderingTiebreaker> tiebreaker,
      Predicate<DomainEvent> skipEvent
   ) {
      this.eventOutboxRepository = eventOutboxRepository;
      this.outboxEventSerializer = outboxEventSerializer;
      this.tiebreaker = tiebreaker;
      this.skipEvent = skipEvent;
   }

   @Override
   public void publish(DomainEvent event) {
      if (this.skipEvent.test(event)) {
         LOG.debug("Skipping " + LogUtil.quote(event.displayName()) + " event publishing to outbox.");
      } else {
         LOG.info("Publishing " + LogUtil.quote(event.displayName()) + " event to outbox.");
         EventOutboxRepository.EventOutboxInsertData insertData = EventOutboxRepository.EventOutboxInsertData.builder()
            .eventId(event.id())
            .eventType(event.type())
            .tieBreaker(((EventOrderingTiebreaker)this.tiebreaker.get()).nextSequence())
            .payload(((OutboxEventSerializer)this.outboxEventSerializer.get()).serialize(event))
            .build();
         ((EventOutboxRepository)this.eventOutboxRepository.get()).insert(insertData);
      }
   }
}
