package com.airlock.iam.login.application.configuration.event;

import com.airlock.iam.common.application.configuration.event.EventReadyValueMapProviderConfig;
import com.airlock.iam.common.application.configuration.event.OutboxRepositoryConfig;
import com.airlock.iam.flow.api.application.configuration.valueprovider.ValueMapProviderConfig;
import com.airlock.iam.login.api.application.configuration.event.LoginappDomainEventSubscriberConfig;
import com.airlock.iam.plugin.api.annotation.config.Groups;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.property.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginListProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

@Plugin(description = "Event settings for the Loginapp.")
@Groups(groupSequence = {"Basic Settings", "Outbox Settings"}, openGroups = {"Basic Settings", "Outbox Settings"})
public final class LoginappEventSettingsConfig {
   static final String OUTBOX_SETTINGS = "Outbox Settings";
   @PluginListProperty(
      description = "List of event subscribers. These subscribers receive events exactly once, but since they are\nnot connected to the outbox, no retries are attempted if a subscriber fails (e.g. because a remote\nserver is not available.)",
      optional = false
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private List<LoginappDomainEventSubscriberConfig> eventSubscribers;
   @PluginProperty(
      description = "Settings for the event outbox repository. If configured, all events are stored in an outbox database table until they\nhave successfully been forwarded to a message broker.",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Outbox Settings")
   private OutboxRepositoryConfig outboxRepository;
   @BooleanProperty(
      description = "Whether generic step result events should also be stored in the event outbox.\nGeneric step result events occur much more frequently than any other event types and are typically not of interest to external event consumers.",
      defaultValue = "false",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Outbox Settings")
   private boolean includeGenericStepResultEvents;
   @PluginListProperty(
      description = "\t<p>A list of value map providers which add additional data as <code>customData</code> to events that are stored in the outbox repository.</p>\n\t<p>Note that these values might contain sensitive information such as email addresses or phone numbers.</p>\n",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Outbox Settings")
   private List<EventReadyValueMapProviderConfig> customOutboxData;

   public List<LoginappDomainEventSubscriberConfig> getEventSubscribers() {
      return this.eventSubscribers;
   }

   public Optional<OutboxRepositoryConfig> getOutboxRepository() {
      return Optional.ofNullable(this.outboxRepository);
   }

   public boolean isIncludeGenericStepResultEvents() {
      return this.includeGenericStepResultEvents;
   }

   public List<ValueMapProviderConfig> getCustomOutboxData() {
      return this.customOutboxData.stream().map(ValueMapProviderConfig.class::cast).toList();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static LoginappEventSettingsConfig.LoginappEventSettingsConfigBuilder builder() {
      return new LoginappEventSettingsConfig.LoginappEventSettingsConfigBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public LoginappEventSettingsConfig(
      List<LoginappDomainEventSubscriberConfig> eventSubscribers,
      OutboxRepositoryConfig outboxRepository,
      boolean includeGenericStepResultEvents,
      List<EventReadyValueMapProviderConfig> customOutboxData
   ) {
      this.eventSubscribers = eventSubscribers;
      this.outboxRepository = outboxRepository;
      this.includeGenericStepResultEvents = includeGenericStepResultEvents;
      this.customOutboxData = customOutboxData;
   }

   @SuppressFBWarnings(justification = "generated code")
   public LoginappEventSettingsConfig() {
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class LoginappEventSettingsConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<LoginappDomainEventSubscriberConfig> eventSubscribers;
      @SuppressFBWarnings(justification = "generated code")
      private OutboxRepositoryConfig outboxRepository;
      @SuppressFBWarnings(justification = "generated code")
      private boolean includeGenericStepResultEvents;
      @SuppressFBWarnings(justification = "generated code")
      private List<EventReadyValueMapProviderConfig> customOutboxData;

      @SuppressFBWarnings(justification = "generated code")
      LoginappEventSettingsConfigBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEventSettingsConfig.LoginappEventSettingsConfigBuilder eventSubscriber(LoginappDomainEventSubscriberConfig eventSubscriber) {
         if (this.eventSubscribers == null) {
            this.eventSubscribers = new ArrayList<>();
         }

         this.eventSubscribers.add(eventSubscriber);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEventSettingsConfig.LoginappEventSettingsConfigBuilder eventSubscribers(
         Collection<? extends LoginappDomainEventSubscriberConfig> eventSubscribers
      ) {
         if (eventSubscribers == null) {
            throw new NullPointerException("eventSubscribers cannot be null");
         }

         if (this.eventSubscribers == null) {
            this.eventSubscribers = new ArrayList<>();
         }

         this.eventSubscribers.addAll(eventSubscribers);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEventSettingsConfig.LoginappEventSettingsConfigBuilder clearEventSubscribers() {
         if (this.eventSubscribers != null) {
            this.eventSubscribers.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEventSettingsConfig.LoginappEventSettingsConfigBuilder outboxRepository(OutboxRepositoryConfig outboxRepository) {
         this.outboxRepository = outboxRepository;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEventSettingsConfig.LoginappEventSettingsConfigBuilder includeGenericStepResultEvents(boolean includeGenericStepResultEvents) {
         this.includeGenericStepResultEvents = includeGenericStepResultEvents;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEventSettingsConfig.LoginappEventSettingsConfigBuilder customOutboxData(List<EventReadyValueMapProviderConfig> customOutboxData) {
         this.customOutboxData = customOutboxData;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEventSettingsConfig build() {
         return new LoginappEventSettingsConfig(switch (this.eventSubscribers == null ? 0 : this.eventSubscribers.size()) {
            case 0 -> Collections.emptyList();
            case 1 -> Collections.singletonList(this.eventSubscribers.get(0));
            default -> Collections.unmodifiableList(new ArrayList<>(this.eventSubscribers));
         }, this.outboxRepository, this.includeGenericStepResultEvents, this.customOutboxData);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "LoginappEventSettingsConfig.LoginappEventSettingsConfigBuilder(eventSubscribers="
            + this.eventSubscribers
            + ", outboxRepository="
            + this.outboxRepository
            + ", includeGenericStepResultEvents="
            + this.includeGenericStepResultEvents
            + ", customOutboxData="
            + this.customOutboxData
            + ")";
      }
   }
}
