package com.airlock.iam.common.domain.model.event;

import com.airlock.iam.base.api.domain.model.event.DomainEvent;
import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.common.api.domain.model.contextdata.ContextDataItem;
import com.airlock.iam.common.api.domain.model.event.UserCreated;
import com.airlock.iam.common.application.configuration.event.UserCreatedSubscribedEventConfig;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
import lombok.NonNull;

@LogicForConfig(UserCreatedSubscribedEventConfig.class)
public final class UserCreatedSubscribedEvent implements AdminappSubscribedEvent, LoginappSubscribedEvent {
   private static final ELogger LOG = ELoggerFactory.getLogger(UserCreatedSubscribedEvent.class);
   private static final String CANONICAL_NAME = "com.airlock.iam.common.api.domain.model.event.UserCreated";
   private final ClassNameEventHandler classNameHandler = new ClassNameEventHandler("com.airlock.iam.common.api.domain.model.event.UserCreated");
   private final Provider<Optional<UserCreatedSubscribedEvent.UserCreatedSubscribedEventSettings>> settings;

   @Inject
   public UserCreatedSubscribedEvent(Provider<Optional<UserCreatedSubscribedEvent.UserCreatedSubscribedEventSettings>> settings) {
      this.settings = settings;
   }

   @Override
   public String subscribedEventClass() {
      return "com.airlock.iam.common.api.domain.model.event.UserCreated";
   }

   @Override
   public boolean canHandle(DomainEvent event) {
      return this.classNameHandler.canHandle(event) && this.filter(event);
   }

   private boolean filter(DomainEvent event) {
      return event instanceof UserCreated userCreatedEvent && this.contextMatch(userCreatedEvent);
   }

   private boolean contextMatch(UserCreated event) {
      if (((Optional)this.settings.get()).isEmpty()) {
         return true;
      }

      Pattern matchingPattern = ((UserCreatedSubscribedEvent.UserCreatedSubscribedEventSettings)((Optional)this.settings.get()).get()).matchingPattern;
      String contextDataKey = ((UserCreatedSubscribedEvent.UserCreatedSubscribedEventSettings)((Optional)this.settings.get()).get()).contextDataKey;
      Optional<ContextDataItem<Object>> contextDataItem = event.contextData().find(contextDataKey);
      if (contextDataItem.isEmpty()) {
         LOG.debug("Context value for key '%s' not available, defaulting to empty string.".formatted(contextDataKey));
      }

      String contextDataValue = contextDataItem.map(ContextDataItem::getValue).map(v -> Objects.toString(v, "")).orElse("");
      boolean isMatch = matchingPattern.matcher(contextDataValue).matches();
      if (isMatch) {
         LOG.debug("Context value for key '%s' is matched by pattern '%s'. Handling event.".formatted(contextDataKey, matchingPattern.toString()));
      } else {
         LOG.debug("Context value for key '%s' is not matched by pattern '%s'. Not handling event.".formatted(contextDataKey, matchingPattern.toString()));
      }

      return isMatch;
   }

   public record UserCreatedSubscribedEventSettings(@NonNull Pattern matchingPattern, @NonNull String contextDataKey) {
      @SuppressFBWarnings(justification = "generated code")
      public UserCreatedSubscribedEventSettings {
         if (matchingPattern == null) {
            throw new NullPointerException("matchingPattern is marked non-null but is null");
         }

         if (contextDataKey == null) {
            throw new NullPointerException("contextDataKey is marked non-null but is null");
         }
      }
   }
}
