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.event.UserRolesChanged;
import com.airlock.iam.common.api.domain.model.role.Role;
import com.airlock.iam.common.application.configuration.event.UserRolesChangedSubscribedEventConfig;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

@LogicForConfig(UserRolesChangedSubscribedEventConfig.class)
public final class UserRolesChangedSubscribedEvent implements AdminappSubscribedEvent {
   private static final String CANONICAL_NAME = "com.airlock.iam.common.api.domain.model.event.UserRolesChanged";
   private final ClassNameEventHandler classNameHandler = new ClassNameEventHandler("com.airlock.iam.common.api.domain.model.event.UserRolesChanged");
   private final Provider<UserRolesChangedSubscribedEvent.UserRolesChangedSubscribedEventSettings> settings;

   @Inject
   public UserRolesChangedSubscribedEvent(Provider<UserRolesChangedSubscribedEvent.UserRolesChangedSubscribedEventSettings> settings) {
      this.settings = settings;
   }

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

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

   private boolean filter(DomainEvent event) {
      return event instanceof UserRolesChanged && this.roleMatchesPattern((UserRolesChanged)event);
   }

   private boolean roleMatchesPattern(UserRolesChanged event) {
      Set<Role> relevantRoles = new HashSet<>();
      if (((UserRolesChangedSubscribedEvent.UserRolesChangedSubscribedEventSettings)this.settings.get()).handleAddedRoles) {
         relevantRoles.addAll(event.addedRoles());
      }

      if (((UserRolesChangedSubscribedEvent.UserRolesChangedSubscribedEventSettings)this.settings.get()).handleRemovedRoles) {
         relevantRoles.addAll(event.removedRoles());
      }

      return relevantRoles.stream()
         .anyMatch(
            r -> ((UserRolesChangedSubscribedEvent.UserRolesChangedSubscribedEventSettings)this.settings.get()).roleFilter.matcher(r.getRoleName()).matches()
         );
   }

   public record UserRolesChangedSubscribedEventSettings(Pattern roleFilter, boolean handleAddedRoles, boolean handleRemovedRoles) {
   }
}
