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

import com.airlock.iam.core.misc.cronto.CrontoHandler;
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.api.domain.model.tag.TagName;
import com.airlock.iam.flow.shared.domain.model.cronto.CrontoActivationStep;
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;
import java.util.Optional;

@Plugin(description = "Configuration for a Cronto activation flow step.", displayName = "Cronto Activation Step")
@PluginLicenseRestriction(moduleAffiliation = "Cronto")
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control", "Advanced Settings"})
@NextActions(CrontoActivationStep.CrontoActivationStepActions.class)
public class CrontoActivationStepConfig extends AbstractInteractiveFlowStepConfig implements StepConfigForAuthenticationFlows, StepConfigForSelfServiceFlows {
   @PluginProperty(description = "Plugin to handle all Cronto-specific actions.", globalPluginReference = "globalCrontoSettings", optional = false)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private CrontoHandler crontoHandler;
   @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 = "CRONTO",
      maxLength = 23,
      optional = true
   )
   private String authenticationMethodId;
   @GroupProperty(groupIdentifier = "Advanced Settings")
   @PluginProperty(
      description = "<p>If configured, this tag indicates strong authentication (typically two factors) and thus enables Cronto on-screen activation. The configured tag has to be obtained by an authentication step. In addition, the property \"Enable On-Screen Activation\" on the Cronto Handler must be enabled and all described conditions of the property must be fulfilled. This feature is typically used for migration use cases.</p><p>For security reasons, it is important to configure a strong authentication tag.</p>",
      optional = true
   )
   private TagConfig strongAuthenticationTag;

   public Optional<TagName> getStrongAuthTagName() {
      return Optional.ofNullable(this.strongAuthenticationTag).map(TagConfig::name);
   }

   protected CrontoActivationStepConfig(
      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,
      CrontoHandler crontoHandler,
      String authenticationMethodId,
      TagConfig strongAuthenticationTag
   ) {
      super(
         skipCondition,
         preCondition,
         requiresActivation,
         tagsOnSuccess,
         stepId,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes
      );
      this.crontoHandler = crontoHandler;
      this.authenticationMethodId = authenticationMethodId;
      this.strongAuthenticationTag = strongAuthenticationTag;
   }

   public CrontoHandler getCrontoHandler() {
      return this.crontoHandler;
   }

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

   public TagConfig getStrongAuthenticationTag() {
      return this.strongAuthenticationTag;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class CrontoActivationStepConfigBuilder {
      @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 CrontoHandler crontoHandler;
      @SuppressFBWarnings(justification = "generated code")
      private String authenticationMethodId;
      @SuppressFBWarnings(justification = "generated code")
      private TagConfig strongAuthenticationTag;

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

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

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

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

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

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

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public CrontoActivationStepConfig.CrontoActivationStepConfigBuilder crontoHandler(CrontoHandler crontoHandler) {
         this.crontoHandler = crontoHandler;
         return this;
      }

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

      @SuppressFBWarnings(justification = "generated code")
      public CrontoActivationStepConfig.CrontoActivationStepConfigBuilder strongAuthenticationTag(TagConfig strongAuthenticationTag) {
         this.strongAuthenticationTag = strongAuthenticationTag;
         return this;
      }

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

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "CrontoActivationStepConfig.CrontoActivationStepConfigBuilder(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
            + ", crontoHandler="
            + this.crontoHandler
            + ", authenticationMethodId="
            + this.authenticationMethodId
            + ", strongAuthenticationTag="
            + this.strongAuthenticationTag
            + ")";
      }
   }
}
