package com.airlock.iam.authentication.application.configuration.airlock2fa;

import com.airlock.iam.factor.application.configuration.airlock2fa.Airlock2FASettings;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FACooldownSettings;
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.api.application.configuration.message.Airlock2FAMessageProviderConfig;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForAuthenticationFlows;
import com.airlock.iam.plugin.api.annotation.config.Groups;
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.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.IntegerProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Plugin(
   description = "<p>Step for Airlock 2FA Usernameless QR Code authentication.</p><p>This step allows authentication without requiring the user to enter their username. Instead, a QR code (identifying the session) is displayed on the login page and can be scanned by any user with the Airlock 2FA app. The app then authenticates this session on the server and thus enables Airlock IAM to connect the browser session with the user who scanned the QR code.</p>",
   displayName = "Airlock 2FA Usernameless Authentication Step"
)
@PluginLicenseRestriction(moduleAffiliation = "Airlock2FA")
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control", "Advanced Settings"})
public class Airlock2FAUsernamelessQrCodeAuthenticationStepConfig extends AbstractInteractiveFlowStepConfig implements StepConfigForAuthenticationFlows {
   public static final String AIRLOCK_2FA_USERNAMELESS_QR_CODE_AUTHENTICATON_STEP_PLUGIN_NAME = "Airlock 2FA Usernameless Authentication Step";
   @PluginProperty(
      displayName = "Airlock 2FA Settings",
      description = "Settings of Airlock 2FA.",
      optional = false,
      globalPluginReference = "globalAirlock2FASettings"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private Airlock2FASettings airlock2faSettings;
   @PluginProperty(
      description = "<p>Creates the message that will be displayed on the user's device when using Usernameless QR Code.\nIf no message provider is configured, the default title of Futurae will be shown (without any additional information items).</p>\n<p>Note that since no user ID is known when creating a username-less QR code, no message providers relying on user-specific data can be used.</p>",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private Airlock2FAMessageProviderConfig messageProvider;
   @IntegerProperty(
      description = "The amount of time a QR Code is valid in seconds.",
      displayName = "QR Code Validity [s]",
      optional = true,
      defaultValue = 60,
      minValue = 30,
      maxValue = 120,
      exampleValues = {30, 60, 120}
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private int qrCodeValidity;
   @IntegerProperty(
      description = "The maximum number of times the QR code is renewed, which means that it is replaced by an unrelated new QR code. <p>QR codes will be renewed already before they expire. This ensures that users can complete ongoing authentication seamlessly even if they scan a QR code shortly before it is refreshed.</p><p>Fewer renewals do not lead to enhanced security. The only reason not to renew indefinitely is to save server resources.</p>",
      displayName = "Maximum QR Code Renewals",
      optional = true,
      defaultValue = 10,
      minValue = 0,
      exampleValues = {0, 5, 10}
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private int maxRenewals;
   @PluginProperty(description = "The ID of the target step to go to on timeout.", displayName = "Timeout Goto Target", optional = true)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private StepIdConfig timeoutGoto;
   @BooleanProperty(
      description = "<p>If enabled, devices in cooldown cannot be used for authentication.</p><p>If disabled, the step ignores the \"Cooldown Period\" for new devices configured in the \"Airlock 2FA Settings\". This is typically used for authentication steps that protect low-risk applications, such as a portal page, which can also be accessed using devices in cooldown.</p><p>If no \"Cooldown Period\" is defined, enabling this property has no effect.</p>",
      displayName = "Respect Cooldown Period",
      optional = true,
      defaultValue = "true"
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private boolean respectCooldownPeriod;

   @Override
   public List<StepIdConfig> getInternalGotoTargets() {
      return this.timeoutGoto == null ? Collections.emptyList() : List.of(this.timeoutGoto);
   }

   public Airlock2FACooldownSettings getCooldownSettings() {
      return new Airlock2FACooldownSettings(this.airlock2faSettings.getCooldownDuration(), this.respectCooldownPeriod);
   }

   public Airlock2FAUsernamelessQrCodeAuthenticationStepConfig(
      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,
      Airlock2FAMessageProviderConfig messageProvider,
      int qrCodeValidity,
      int maxRenewals,
      StepIdConfig timeoutGoto,
      boolean respectCooldownPeriod
   ) {
      super(
         skipCondition,
         preCondition,
         requiresActivation,
         tagsOnSuccess,
         stepId,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes
      );
      this.airlock2faSettings = airlock2faSettings;
      this.messageProvider = messageProvider;
      this.qrCodeValidity = qrCodeValidity;
      this.maxRenewals = maxRenewals;
      this.timeoutGoto = timeoutGoto;
      this.respectCooldownPeriod = respectCooldownPeriod;
   }

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

   public int getQrCodeValidity() {
      return this.qrCodeValidity;
   }

   public int getMaxRenewals() {
      return this.maxRenewals;
   }

   @Nullable
   public StepIdConfig getTimeoutGoto() {
      return this.timeoutGoto;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class Airlock2FAUsernamelessQrCodeAuthenticationStepConfigBuilder {
      @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 Airlock2FAMessageProviderConfig messageProvider;
      @SuppressFBWarnings(justification = "generated code")
      private int qrCodeValidity;
      @SuppressFBWarnings(justification = "generated code")
      private int maxRenewals;
      @SuppressFBWarnings(justification = "generated code")
      private StepIdConfig timeoutGoto;
      @SuppressFBWarnings(justification = "generated code")
      private boolean respectCooldownPeriod;

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

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

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

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

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

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

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

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUsernamelessQrCodeAuthenticationStepConfig.Airlock2FAUsernamelessQrCodeAuthenticationStepConfigBuilder messageProvider(
         Airlock2FAMessageProviderConfig messageProvider
      ) {
         this.messageProvider = messageProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUsernamelessQrCodeAuthenticationStepConfig.Airlock2FAUsernamelessQrCodeAuthenticationStepConfigBuilder qrCodeValidity(int qrCodeValidity) {
         this.qrCodeValidity = qrCodeValidity;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUsernamelessQrCodeAuthenticationStepConfig.Airlock2FAUsernamelessQrCodeAuthenticationStepConfigBuilder maxRenewals(int maxRenewals) {
         this.maxRenewals = maxRenewals;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUsernamelessQrCodeAuthenticationStepConfig.Airlock2FAUsernamelessQrCodeAuthenticationStepConfigBuilder timeoutGoto(
         StepIdConfig timeoutGoto
      ) {
         this.timeoutGoto = timeoutGoto;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUsernamelessQrCodeAuthenticationStepConfig.Airlock2FAUsernamelessQrCodeAuthenticationStepConfigBuilder respectCooldownPeriod(
         boolean respectCooldownPeriod
      ) {
         this.respectCooldownPeriod = respectCooldownPeriod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUsernamelessQrCodeAuthenticationStepConfig build() {
         return new Airlock2FAUsernamelessQrCodeAuthenticationStepConfig(
            this.skipCondition,
            this.preCondition,
            this.requiresActivation,
            this.tagsOnSuccess,
            this.stepId,
            this.interactiveGotoTargets,
            this.dynamicStepActivations,
            this.onFailureGotos,
            this.customResponseAttributes,
            this.customFailureResponseAttributes,
            this.airlock2faSettings,
            this.messageProvider,
            this.qrCodeValidity,
            this.maxRenewals,
            this.timeoutGoto,
            this.respectCooldownPeriod
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "Airlock2FAUsernamelessQrCodeAuthenticationStepConfig.Airlock2FAUsernamelessQrCodeAuthenticationStepConfigBuilder(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
            + ", messageProvider="
            + this.messageProvider
            + ", qrCodeValidity="
            + this.qrCodeValidity
            + ", maxRenewals="
            + this.maxRenewals
            + ", timeoutGoto="
            + this.timeoutGoto
            + ", respectCooldownPeriod="
            + this.respectCooldownPeriod
            + ")";
      }
   }
}
