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

import com.airlock.iam.factor.application.configuration.fido.FidoSettingsConfig;
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.types.api.application.configuration.step.StepConfigForAuthenticationFlows;
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.PluginMapProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.List;
import java.util.Map;

@PluginLicenseRestriction(moduleAffiliation = "FIDO")
@Plugin(
   displayName = "FIDO Passwordless Authentication Step",
   description = "<p>Step to identify and authenticate a user with a FIDO authenticator.\nThis step is passwordless meaning that the user is not required to input a username nor a password in a previous step.</p>\n<p>Passwordless authentication requires the use of resident key,\nwhere the key material is stored on the FIDO authenticator. This needs to be enforced at registration\nby ensuring that \"Require Resident Key\" in \"FIDO Settings\" is enabled.\nPlease refer to the documentation for more details about the requirements of FIDO passwordless authentication.\nFurthermore, transports cannot be restricted in passwordless mode.</p>"
)
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control"})
@NextActions(FidoAuthenticationStepActions.Action.class)
public final class FidoPasswordlessAuthenticationStepConfig extends AbstractInteractiveFlowStepConfig implements StepConfigForAuthenticationFlows {
   public static final String FIDO_PASSWORDLESS_AUTHENTICATION_STEP_PLUGIN_NAME = "FIDO Passwordless Authentication Step";
   @PluginProperty(displayName = "FIDO Settings", description = "Settings for FIDO.", optional = false, globalPluginReference = "globalFidoSettings")
   @GroupProperty(groupIdentifier = "Basic Settings")
   private FidoSettingsConfig fidoSettings;
   @PluginMapProperty(
      description = "<p>If the step fails (no retry) and a goto target for the error code is defined here, the flow does not fail\nand instead a \"goto\" to the specified target step is executed. Note that even when the \"goto\" is executed, any\nerror codes that are considered a failed factor attempt will still increment the \"failed attempts\" counter,\nand may lead to the user being locked. Therefore, this may still result in a failed flow.</p>\n<p>This step can return the following error codes:\n<ul>\n  <li><code>FIDO_AUTHENTICATION_FAILED</code>: The FIDO authentication failed for unspecified reasons (either in the browser/client or during server-side verification).</li>\n  <li><code>FIDO_AUTHENTICATION_TIMEOUT</code>: The response from the browser/client has timed out.</li>\n  <li><code>FIDO_AUTHENTICATION_ABORTED</code>: The authentication has been aborted in the browser/client.</li>\n  <li><code>FIDO_AUTHENTICATION_NOT_ALLOWED</code>: The browser/client did not allow authentication with the given credentials.</li>\n  <li><code>FIDO_WEB_AUTHN_NOT_AVAILABLE</code>: The client/browser is not capable of performing WebAuthn/FIDO authentication.</li>\n</ul></p>\n",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Flow Control")
   private Map<String, StepIdConfig> onFailureGotos;

   public FidoSettingsConfig getFidoSettings() {
      return this.fidoSettings;
   }

   @Override
   public Map<String, StepIdConfig> getOnFailureGotos() {
      return this.onFailureGotos;
   }

   private FidoPasswordlessAuthenticationStepConfig(
      FlowConditionConfig skipCondition,
      FlowConditionConfig preCondition,
      boolean requiresActivation,
      List<TagConfig> tagsOnSuccess,
      @Nullable StepIdConfig stepId,
      FidoSettingsConfig fidoSettings,
      List<InteractiveGotoTargetConfig> interactiveGotoTargets,
      List<DynamicStepActivationConfig> dynamicStepActivations,
      Map<String, StepIdConfig> onFailureGotos,
      List<ValueMapProviderConfig> customResponseAttributes,
      List<ValueMapProviderConfig> customFailureResponseAttributes
   ) {
      super(
         skipCondition,
         preCondition,
         requiresActivation,
         tagsOnSuccess,
         stepId,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes
      );
      this.fidoSettings = fidoSettings;
      this.onFailureGotos = onFailureGotos;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class FidoPasswordlessAuthenticationStepConfigBuilder {
      @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 FidoSettingsConfig fidoSettings;
      @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")
      FidoPasswordlessAuthenticationStepConfigBuilder() {
      }

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public FidoPasswordlessAuthenticationStepConfig.FidoPasswordlessAuthenticationStepConfigBuilder fidoSettings(FidoSettingsConfig fidoSettings) {
         this.fidoSettings = fidoSettings;
         return this;
      }

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

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

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

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

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

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

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