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

import com.airlock.iam.common.api.application.configuration.cronto.CrontoMessageProviderConfig;
import com.airlock.iam.core.domain.model.cronto.CrontoCheckingSettings;
import com.airlock.iam.core.misc.cronto.CrontoHandler;
import com.airlock.iam.core.misc.plugin.config.validation.CrontoConfigValidator;
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.cronto.CommonCrontoCheckingStepConfig;
import com.airlock.iam.flow.shared.application.configuration.message.DefaultCrontoLoginMessageProviderConfig;
import com.airlock.iam.flow.shared.domain.model.cronto.CrontoCheckingStep;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForAuthenticationFlows;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
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.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.Environment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.exception.PropertyTypeMismatchException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.List;
import java.util.Map;

@Plugin(description = "Configuration for a Cronto authentication flow step.", displayName = "Cronto Authentication Step")
@PluginLicenseRestriction(moduleAffiliation = "Cronto")
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control", "Advanced Settings"})
@NextActions(CrontoCheckingStep.CrontoAuthStepActions.class)
public class CrontoAuthStepConfig extends CommonCrontoCheckingStepConfig implements StepConfigForAuthenticationFlows {
   @BooleanProperty(
      description = "<p>If this flag is set and there is no push-enabled device for the user, authentication is not possible.</p><p>This feature may be used for mobile application logins, where showing a cryptogram on the same device is not appropriate.</p>",
      defaultValue = "false",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private boolean authenticatePushDevicesOnly;
   @BooleanProperty(
      description = "If enabled, the step also asks for push device selection if there is only one push device enabled. Since the selection always includes the \"offline\" option, this can be used for \"app-to-app\" setups, where push messages should never be sent.",
      defaultValue = "false",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private boolean pushSelectionForSingleDevice;
   @BooleanProperty(
      description = "<p>If this flag is set a random ID is generated and shown to the user during push login.</p><p>The ID is shown on the Cronto device with the push message and on the login page, allowing the user to correlate a push message with a login session.</p>",
      defaultValue = "false",
      optional = true,
      displayName = "Show Login ID On Push"
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private boolean showLoginIdOnPush;
   private static final String FIELD_SHOW_LOGIN_ID_ON_PUSH = "showLoginIdOnPush";
   @PluginProperty(
      description = "Message provider to create the login message.",
      optional = true,
      defaultValue = DefaultCrontoLoginMessageProviderConfig.class
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private CrontoMessageProviderConfig messageProvider;

   public CrontoCheckingSettings getSettings() {
      return CrontoCheckingSettings.builder()
         .authenticatePushDevicesOnly(this.authenticatePushDevicesOnly)
         .pushSelectionForSingleDevice(this.pushSelectionForSingleDevice)
         .pushToAllDevices(false)
         .showLoginIdOnPush(this.showLoginIdOnPush)
         .maxResponseRetries(this.getMaxResponseRetries())
         .crontoHandler(this.getCrontoHandler())
         .challengeType(CrontoHandler.CrontoChallengeType.LOGIN)
         .build();
   }

   @ConfigurationValidator
   static void checkPushIsEnabledWhenPushLoginIdIsEnabled(
      PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment valenv
   ) throws PropertyConstraintViolationException, PropertyTypeMismatchException {
      CrontoConfigValidator.validatePushIsEnabledWhenPushLoginIdIsEnabled(config, "showLoginIdOnPush", "crontoHandler", env, context);
   }

   protected CrontoAuthStepConfig(
      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,
      int maxResponseRetries,
      boolean authenticatePushDevicesOnly,
      boolean pushSelectionForSingleDevice,
      boolean showLoginIdOnPush,
      CrontoMessageProviderConfig messageProvider,
      String authenticationMethodId
   ) {
      super(
         skipCondition,
         preCondition,
         requiresActivation,
         tagsOnSuccess,
         stepId,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes,
         crontoHandler,
         maxResponseRetries,
         authenticationMethodId
      );
      this.authenticatePushDevicesOnly = authenticatePushDevicesOnly;
      this.pushSelectionForSingleDevice = pushSelectionForSingleDevice;
      this.showLoginIdOnPush = showLoginIdOnPush;
      this.messageProvider = messageProvider;
   }

   public boolean isAuthenticatePushDevicesOnly() {
      return this.authenticatePushDevicesOnly;
   }

   public boolean isPushSelectionForSingleDevice() {
      return this.pushSelectionForSingleDevice;
   }

   public boolean isShowLoginIdOnPush() {
      return this.showLoginIdOnPush;
   }

   public CrontoMessageProviderConfig getMessageProvider() {
      return this.messageProvider;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class CrontoAuthStepConfigBuilder {
      @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 int maxResponseRetries;
      @SuppressFBWarnings(justification = "generated code")
      private boolean authenticatePushDevicesOnly;
      @SuppressFBWarnings(justification = "generated code")
      private boolean pushSelectionForSingleDevice;
      @SuppressFBWarnings(justification = "generated code")
      private boolean showLoginIdOnPush;
      @SuppressFBWarnings(justification = "generated code")
      private CrontoMessageProviderConfig messageProvider;
      @SuppressFBWarnings(justification = "generated code")
      private String authenticationMethodId;

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

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

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

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

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

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

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

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public CrontoAuthStepConfig.CrontoAuthStepConfigBuilder maxResponseRetries(int maxResponseRetries) {
         this.maxResponseRetries = maxResponseRetries;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CrontoAuthStepConfig.CrontoAuthStepConfigBuilder authenticatePushDevicesOnly(boolean authenticatePushDevicesOnly) {
         this.authenticatePushDevicesOnly = authenticatePushDevicesOnly;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CrontoAuthStepConfig.CrontoAuthStepConfigBuilder pushSelectionForSingleDevice(boolean pushSelectionForSingleDevice) {
         this.pushSelectionForSingleDevice = pushSelectionForSingleDevice;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CrontoAuthStepConfig.CrontoAuthStepConfigBuilder showLoginIdOnPush(boolean showLoginIdOnPush) {
         this.showLoginIdOnPush = showLoginIdOnPush;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CrontoAuthStepConfig.CrontoAuthStepConfigBuilder messageProvider(CrontoMessageProviderConfig messageProvider) {
         this.messageProvider = messageProvider;
         return this;
      }

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

      @SuppressFBWarnings(justification = "generated code")
      public CrontoAuthStepConfig build() {
         return new CrontoAuthStepConfig(
            this.skipCondition,
            this.preCondition,
            this.requiresActivation,
            this.tagsOnSuccess,
            this.stepId,
            this.interactiveGotoTargets,
            this.dynamicStepActivations,
            this.onFailureGotos,
            this.customResponseAttributes,
            this.customFailureResponseAttributes,
            this.crontoHandler,
            this.maxResponseRetries,
            this.authenticatePushDevicesOnly,
            this.pushSelectionForSingleDevice,
            this.showLoginIdOnPush,
            this.messageProvider,
            this.authenticationMethodId
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "CrontoAuthStepConfig.CrontoAuthStepConfigBuilder(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
            + ", maxResponseRetries="
            + this.maxResponseRetries
            + ", authenticatePushDevicesOnly="
            + this.authenticatePushDevicesOnly
            + ", pushSelectionForSingleDevice="
            + this.pushSelectionForSingleDevice
            + ", showLoginIdOnPush="
            + this.showLoginIdOnPush
            + ", messageProvider="
            + this.messageProvider
            + ", authenticationMethodId="
            + this.authenticationMethodId
            + ")";
      }
   }
}
