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

import com.airlock.iam.common.application.configuration.event.GatewayRestApiConnectionConfig;
import com.airlock.iam.common.application.configuration.event.LoginappUserSubscribedEventConfig;
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.PluginListProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

@Plugin(
   description = "<p>This event subscriber terminates a user's Airlock Gateway sessions. Upon an event trigger, the plugin contacts\none or more Airlock Gateways via their REST APIs, terminating all sessions, optionally excluding the current user's active session.\nIn clustered gateway deployments, it is sufficient to contact a single gateway node to invalidate the user’s sessions across the cluster.</p>\n<p>For consistency, consider subscribing to the same events used by the 'Gateway Session Terminator Subscriber (Adminapp)'.</p>\n<p>Prerequisites:</p>\n<ul><li>The Gateway Audit Token must be configured to contain only the <tt>username</tt></li>\n<li>IAM must be able to open HTTP(S) connections to the Airlock Gateways. This may require changes to your network topology.</li></ul>\n<p><em>Security Advisory:</em> Certain events (e.g., “Generic Step Result With Identified User”) can be triggered without an authenticated\nuser session. Under Denial-of-Service conditions, such events may result in unintended session terminations and should therefore be selected with caution.</p>\n",
   displayName = "Gateway Session Terminator Subscriber (Loginapp)"
)
public class LoginappGatewaySessionTerminatorEventSubscriberConfig extends LoginappUserEventSubscriberConfig {
   @PluginListProperty(
      description = "The Airlock Gateway REST APIs that are invoked to terminate the user's sessions.",
      displayName = "Gateway REST APIs",
      optional = false,
      minElements = 1
   )
   private List<GatewayRestApiConnectionConfig> gatewayRestApiConnections;
   @BooleanProperty(
      description = "If enabled, the user's currently active session is not terminated. For example, if this event subscriber listens for password\nchanges and this flag is enabled, a user's active session will not be terminated when they change their own password.\n",
      optional = true,
      defaultValue = "true"
   )
   private boolean keepCurrentUserSession;

   public LoginappGatewaySessionTerminatorEventSubscriberConfig(
      LoginappUserSubscribedEventConfig event, @Nonnull List<GatewayRestApiConnectionConfig> gatewayRestApiConnections, boolean keepCurrentUserSession
   ) {
      super(event);
      this.gatewayRestApiConnections = gatewayRestApiConnections;
      this.keepCurrentUserSession = keepCurrentUserSession;
   }

   @Nonnull
   public List<GatewayRestApiConnectionConfig> getGatewayRestApiConnections() {
      return this.gatewayRestApiConnections;
   }

   public boolean isKeepCurrentUserSession() {
      return this.keepCurrentUserSession;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class LoginappGatewaySessionTerminatorEventSubscriberConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private LoginappUserSubscribedEventConfig event;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<GatewayRestApiConnectionConfig> gatewayRestApiConnections;
      @SuppressFBWarnings(justification = "generated code")
      private boolean keepCurrentUserSession;

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

      @SuppressFBWarnings(justification = "generated code")
      public LoginappGatewaySessionTerminatorEventSubscriberConfig.LoginappGatewaySessionTerminatorEventSubscriberConfigBuilder event(
         LoginappUserSubscribedEventConfig event
      ) {
         this.event = event;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappGatewaySessionTerminatorEventSubscriberConfig.LoginappGatewaySessionTerminatorEventSubscriberConfigBuilder gatewayRestApiConnection(
         GatewayRestApiConnectionConfig gatewayRestApiConnection
      ) {
         if (this.gatewayRestApiConnections == null) {
            this.gatewayRestApiConnections = new ArrayList<>();
         }

         this.gatewayRestApiConnections.add(gatewayRestApiConnection);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappGatewaySessionTerminatorEventSubscriberConfig.LoginappGatewaySessionTerminatorEventSubscriberConfigBuilder gatewayRestApiConnections(
         Collection<? extends GatewayRestApiConnectionConfig> gatewayRestApiConnections
      ) {
         if (gatewayRestApiConnections == null) {
            throw new NullPointerException("gatewayRestApiConnections cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public LoginappGatewaySessionTerminatorEventSubscriberConfig.LoginappGatewaySessionTerminatorEventSubscriberConfigBuilder clearGatewayRestApiConnections() {
         if (this.gatewayRestApiConnections != null) {
            this.gatewayRestApiConnections.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappGatewaySessionTerminatorEventSubscriberConfig.LoginappGatewaySessionTerminatorEventSubscriberConfigBuilder keepCurrentUserSession(
         boolean keepCurrentUserSession
      ) {
         this.keepCurrentUserSession = keepCurrentUserSession;
         return this;
      }

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

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "LoginappGatewaySessionTerminatorEventSubscriberConfig.LoginappGatewaySessionTerminatorEventSubscriberConfigBuilder(event="
            + this.event
            + ", gatewayRestApiConnections="
            + this.gatewayRestApiConnections
            + ", keepCurrentUserSession="
            + this.keepCurrentUserSession
            + ")";
      }
   }
}
