package com.airlock.iam.flow.shared.application.configuration.airlock2fa;

import com.airlock.iam.factor.application.configuration.airlock2fa.Airlock2FASettings;
import com.airlock.iam.flow.api.application.configuration.dynamicactivation.DynamicStepActivationConfig;
import com.airlock.iam.flow.api.application.configuration.selection.FlowConditionConfig;
import com.airlock.iam.flow.api.application.configuration.step.AbstractInteractiveFlowStepConfig;
import com.airlock.iam.flow.api.application.configuration.step.InteractiveGotoTargetConfig;
import com.airlock.iam.flow.api.application.configuration.step.StepIdConfig;
import com.airlock.iam.flow.api.application.configuration.tag.TagConfig;
import com.airlock.iam.flow.api.application.configuration.valueprovider.ValueMapProviderConfig;
import com.airlock.iam.flow.shared.domain.model.airlock2fa.Airlock2FAActivationFlowBindingStep;
import com.airlock.iam.flow.shared.domain.model.airlock2fa.Airlock2FAActivationStatusStep;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForAuthenticationFlows;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForSelfServiceFlows;
import com.airlock.iam.plugin.api.annotation.config.Groups;
import com.airlock.iam.plugin.api.annotation.config.NextActions;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.license.PluginLicenseRestriction;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.List;
import java.util.Map;

@Plugin(
   description = "This step can be used if an Airlock 2FA activation letter has previously been sent to the user. If 'Trusted Session Binding for Activation' is set to 'Only with Letter' or 'Always' in the 'Airlock 2FA Settings', this step is necessary for users to activate devices using activation letters. Airlock IAM does not provide a UI for this step, since it is intended to be used by custom mobile apps. The intended use-case is a mobile app to scan an activation letter and extract the activation code. The activation code is sent to Airlock IAM, which will return a trusted session binding token. The mobile app can then use the binding token together with the activation code, to complete the Airlock 2FA device activation. If Airlock IAM does not receive a flow binding token from Futurae, it will return an empty response and the step will not fail. <p>This step also provides a REST endpoint to poll the status of an activation.</p>",
   displayName = "Airlock 2FA Activation Trusted Session Binding Step"
)
@PluginLicenseRestriction(moduleAffiliation = "Airlock2FA")
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control"})
@NextActions(
   {Airlock2FAActivationStatusStep.Airlock2FAActivationStepAction.class, Airlock2FAActivationFlowBindingStep.Airlock2FAActivationFlowBindingNextAction.class}
)
public class Airlock2faActivationTrustedSessionBindingStepConfig
   extends AbstractInteractiveFlowStepConfig
   implements StepConfigForAuthenticationFlows,
   StepConfigForSelfServiceFlows {
   @PluginProperty(
      displayName = "Airlock 2FA Settings",
      description = "Settings of Airlock 2FA.",
      optional = false,
      globalPluginReference = "globalAirlock2FASettings"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private Airlock2FASettings airlock2faSettings;
   @GroupProperty(groupIdentifier = "Advanced Settings")
   @StringProperty(
      description = "The identifier of the authentication method for this step. Since the authentication method is also the identifier for failed login attempts for this step, distinct identifiers must be chosen if multiple instances of the same step type are used to check different credentials (e.g., two password step instances check two different passwords).<p>Example: a system tracks two passwords per user. Password 1 is used in flow A, password 2 in flow B. These two steps must have distinct 'Authentication Method Ids', e.g. PASSWORD1 and PASSWORD2.</p>If only one identifier (e.g. \"PASSWORD\") is used, this may allow brute force attacks on the password as follows. Assuming an attacker knows the user's password 1, they get an unlimited number of attempts on flow B, as the 'PASSWORD' counter can repeatedly be reset to 0 by performing a successful login on flow A.<p>To prevent such attacks, use two different counters by setting the authentication methods, for example, to PASSWORD1 and PASSWORD2, respectively.</p>",
      displayName = "Authentication Method ID",
      defaultValue = "AIRLOCK_2FA",
      maxLength = 23,
      optional = true
   )
   private String authenticationMethodId;

   protected Airlock2faActivationTrustedSessionBindingStepConfig(
      FlowConditionConfig skipCondition,
      FlowConditionConfig preCondition,
      boolean requiresActivation,
      List<TagConfig> tagsOnSuccess,
      @Nullable StepIdConfig stepId,
      List<InteractiveGotoTargetConfig> interactiveGotoTargets,
      List<DynamicStepActivationConfig> dynamicStepActivations,
      Map<String, StepIdConfig> onFailureGotos,
      List<ValueMapProviderConfig> customResponseAttributes,
      List<ValueMapProviderConfig> customFailureResponseAttributes,
      Airlock2FASettings airlock2faSettings,
      String authenticationMethodId
   ) {
      super(
         skipCondition,
         preCondition,
         requiresActivation,
         tagsOnSuccess,
         stepId,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes
      );
      this.airlock2faSettings = airlock2faSettings;
      this.authenticationMethodId = authenticationMethodId;
   }

   public Airlock2FASettings getAirlock2faSettings() {
      return this.airlock2faSettings;
   }

   public String getAuthenticationMethodId() {
      return this.authenticationMethodId;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class Airlock2faActivationTrustedSessionBindingStepConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private FlowConditionConfig skipCondition;
      @SuppressFBWarnings(justification = "generated code")
      private FlowConditionConfig preCondition;
      @SuppressFBWarnings(justification = "generated code")
      private boolean requiresActivation;
      @SuppressFBWarnings(justification = "generated code")
      private List<TagConfig> tagsOnSuccess;
      @SuppressFBWarnings(justification = "generated code")
      private StepIdConfig stepId;
      @SuppressFBWarnings(justification = "generated code")
      private List<InteractiveGotoTargetConfig> interactiveGotoTargets;
      @SuppressFBWarnings(justification = "generated code")
      private List<DynamicStepActivationConfig> dynamicStepActivations;
      @SuppressFBWarnings(justification = "generated code")
      private Map<String, StepIdConfig> onFailureGotos;
      @SuppressFBWarnings(justification = "generated code")
      private List<ValueMapProviderConfig> customResponseAttributes;
      @SuppressFBWarnings(justification = "generated code")
      private List<ValueMapProviderConfig> customFailureResponseAttributes;
      @SuppressFBWarnings(justification = "generated code")
      private Airlock2FASettings airlock2faSettings;
      @SuppressFBWarnings(justification = "generated code")
      private String authenticationMethodId;

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

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder skipCondition(
         FlowConditionConfig skipCondition
      ) {
         this.skipCondition = skipCondition;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder preCondition(
         FlowConditionConfig preCondition
      ) {
         this.preCondition = preCondition;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder requiresActivation(
         boolean requiresActivation
      ) {
         this.requiresActivation = requiresActivation;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder tagsOnSuccess(
         List<TagConfig> tagsOnSuccess
      ) {
         this.tagsOnSuccess = tagsOnSuccess;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder stepId(
         @Nullable StepIdConfig stepId
      ) {
         this.stepId = stepId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder interactiveGotoTargets(
         List<InteractiveGotoTargetConfig> interactiveGotoTargets
      ) {
         this.interactiveGotoTargets = interactiveGotoTargets;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder dynamicStepActivations(
         List<DynamicStepActivationConfig> dynamicStepActivations
      ) {
         this.dynamicStepActivations = dynamicStepActivations;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder onFailureGotos(
         Map<String, StepIdConfig> onFailureGotos
      ) {
         this.onFailureGotos = onFailureGotos;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder customResponseAttributes(
         List<ValueMapProviderConfig> customResponseAttributes
      ) {
         this.customResponseAttributes = customResponseAttributes;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder customFailureResponseAttributes(
         List<ValueMapProviderConfig> customFailureResponseAttributes
      ) {
         this.customFailureResponseAttributes = customFailureResponseAttributes;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder airlock2faSettings(
         Airlock2FASettings airlock2faSettings
      ) {
         this.airlock2faSettings = airlock2faSettings;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder authenticationMethodId(
         String authenticationMethodId
      ) {
         this.authenticationMethodId = authenticationMethodId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2faActivationTrustedSessionBindingStepConfig build() {
         return new Airlock2faActivationTrustedSessionBindingStepConfig(
            this.skipCondition,
            this.preCondition,
            this.requiresActivation,
            this.tagsOnSuccess,
            this.stepId,
            this.interactiveGotoTargets,
            this.dynamicStepActivations,
            this.onFailureGotos,
            this.customResponseAttributes,
            this.customFailureResponseAttributes,
            this.airlock2faSettings,
            this.authenticationMethodId
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "Airlock2faActivationTrustedSessionBindingStepConfig.Airlock2faActivationTrustedSessionBindingStepConfigBuilder(skipCondition="
            + this.skipCondition
            + ", preCondition="
            + this.preCondition
            + ", requiresActivation="
            + this.requiresActivation
            + ", tagsOnSuccess="
            + this.tagsOnSuccess
            + ", stepId="
            + this.stepId
            + ", interactiveGotoTargets="
            + this.interactiveGotoTargets
            + ", dynamicStepActivations="
            + this.dynamicStepActivations
            + ", onFailureGotos="
            + this.onFailureGotos
            + ", customResponseAttributes="
            + this.customResponseAttributes
            + ", customFailureResponseAttributes="
            + this.customFailureResponseAttributes
            + ", airlock2faSettings="
            + this.airlock2faSettings
            + ", authenticationMethodId="
            + this.authenticationMethodId
            + ")";
      }
   }
}
