package com.airlock.iam.publicselfservice.application.configuration.steps;

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.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.application.configuration.fido.FidoApprovalStepActions;
import com.airlock.iam.flow.shared.application.configuration.step.CommonFidoCheckingStepConfig;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForPublicSelfServiceFlows;
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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.List;
import java.util.Map;

@PluginLicenseRestriction(moduleAffiliation = "FIDO")
@Plugin(
   description = "<p>Step to approve an operation with FIDO.</p><p>Note that unlike identity verification steps, approval steps require an existing user and cannot prevent username enumeration (no stealth mode). It is therefore important that approval steps are only used <em>after</em> an identity verification step.</p><p>FIDO approval does not allow verification of the data via a separate channel. If this additional level of security is required, use Airlock 2FA, Cronto or mTAN approval.</p>",
   displayName = "FIDO Public Self-Service Approval Step"
)
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control"})
@NextActions(FidoApprovalStepActions.Action.class)
public final class PublicSelfServiceFidoApprovalStepConfig extends CommonFidoCheckingStepConfig implements StepConfigForPublicSelfServiceFlows {
   @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_APPROVAL_FAILED</code>: The FIDO approval failed for unspecified reasons (either in the browser/client or during server-side verification).</li>\n <li><code>FIDO_APPROVAL_TIMEOUT</code>: The response from the browser/client has timed out.</li>\n <li><code>FIDO_APPROVAL_ABORTED</code>: The approval has been aborted in the browser/client.</li>\n <li><code>FIDO_APPROVAL_NOT_ALLOWED</code>: The browser/client did not allow approval with the given credentials.</li>\n <li><code>FIDO_WEB_AUTHN_NOT_AVAILABLE</code>: The browser/client is not capable of performing WebAuthn/FIDO approval.</li>\n <li><code>NO_VALID_TOKEN</code>: The user has no eligible FIDO credential registered.</li>\n</ul></p>\n",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Flow Control")
   private Map<String, StepIdConfig> onFailureGotos;

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

   private PublicSelfServiceFidoApprovalStepConfig(
      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,
         fidoSettings,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes
      );
      this.onFailureGotos = onFailureGotos;
   }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public PublicSelfServiceFidoApprovalStepConfig build() {
         return new PublicSelfServiceFidoApprovalStepConfig(
            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 "PublicSelfServiceFidoApprovalStepConfig.PublicSelfServiceFidoApprovalStepConfigBuilder(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
            + ")";
      }
   }
}
