package com.airlock.iam.authentication.application.configuration.migration.condition;

import com.airlock.iam.flow.api.application.configuration.selection.FlowConditionConfig;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.lifecycle.AfterConfigActivation;
import com.airlock.iam.plugin.api.annotation.property.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
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.ConfigurationException;
import com.airlock.iam.plugin.framework.domain.service.validation.DurationParser;
import com.airlock.iam.plugin.framework.domain.service.validation.DurationValidator;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.time.Duration;

@Plugin(
   description = "Condition that is fulfilled if the configured \"Target Auth Method\" matches the user's next authentication method and the current date is within or after the migration hint period.",
   displayName = "Next Authentication Method-based Migration Condition"
)
public final class NextAuthMethodBasedMigrationConditionConfig implements FlowConditionConfig {
   public static final String DEFAULT_HINT_PERIOD = "10d";
   public static final String MIGRATION_CONDITION_DISPLAY_NAME = "Next Authentication Method-based Migration Condition";
   @StringProperty(
      description = "Expected value of the next auth method field on the user for this condition to be fulfilled.",
      optional = false,
      suggestedValues = {"MTAN", "CRONTO", "DEVICE_TOKEN", "MATRIX"}
   )
   private String targetAuthMethod;
   @StringProperty(
      description = "Ask the user to migrate during this period before the migration becomes mandatory.\nAny immediate period (e.g. 0d) leads to the users always being forced to migrate at the migration date\nand the migration hint page never being displayed before.\n<p/>To always show the migration hint page as soon as a migration date is set for a user, set this property to a very high value.<p/>\nNotice that this setting has no effect if the user has a \"Next Auth Method\" but no migration date set;\nin this case the user is always displayed the migration hint page and never forced to migrate.\n<p>The duration must be specified in the format \"(d)ays (h)ours (m)inutes (s)econds\" e.g. \"2d 4h 10m 5s\" (any part can be omitted).</p>",
      displayName = "Hint Period",
      optional = true,
      defaultValue = "10d",
      exampleValues = {"7d", "30d", "14d 6h 30m"}
   )
   private String hintPeriod;
   private static final String HINT_PERIOD_PROPERTY = "hintPeriod";
   private Duration hintPeriodDuration;
   @BooleanProperty(
      description = "Defines whether the migration to the same authentication method the user already has is allowed.",
      optional = true,
      defaultValue = "true"
   )
   private boolean migrationToSameAuthMethodAllowed;

   private NextAuthMethodBasedMigrationConditionConfig(String targetAuthMethod, String hintPeriod, boolean migrationToSameAuthMethodAllowed) {
      this.targetAuthMethod = targetAuthMethod;
      this.hintPeriod = hintPeriod;
      this.migrationToSameAuthMethodAllowed = migrationToSameAuthMethodAllowed;
   }

   @ConfigurationValidator
   public static void validateHintPeriodDuration(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment valEnv) throws ConfigurationException {
      DurationValidator.validateDurationFieldIfSet(config, "hintPeriod", env, context);
   }

   @AfterConfigActivation
   void parseHintPeriodDuration() {
      this.hintPeriodDuration = new DurationParser(this.hintPeriod).getDuration();
   }

   public String getTargetAuthMethod() {
      return this.targetAuthMethod;
   }

   public String getHintPeriod() {
      return this.hintPeriod;
   }

   public Duration getHintPeriodDuration() {
      return this.hintPeriodDuration;
   }

   public boolean isMigrationToSameAuthMethodAllowed() {
      return this.migrationToSameAuthMethodAllowed;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class NextAuthMethodBasedMigrationConditionConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String targetAuthMethod;
      @SuppressFBWarnings(justification = "generated code")
      private String hintPeriod;
      @SuppressFBWarnings(justification = "generated code")
      private boolean migrationToSameAuthMethodAllowed;

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

      @SuppressFBWarnings(justification = "generated code")
      public NextAuthMethodBasedMigrationConditionConfig.NextAuthMethodBasedMigrationConditionConfigBuilder targetAuthMethod(String targetAuthMethod) {
         this.targetAuthMethod = targetAuthMethod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public NextAuthMethodBasedMigrationConditionConfig.NextAuthMethodBasedMigrationConditionConfigBuilder hintPeriod(String hintPeriod) {
         this.hintPeriod = hintPeriod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public NextAuthMethodBasedMigrationConditionConfig.NextAuthMethodBasedMigrationConditionConfigBuilder migrationToSameAuthMethodAllowed(
         boolean migrationToSameAuthMethodAllowed
      ) {
         this.migrationToSameAuthMethodAllowed = migrationToSameAuthMethodAllowed;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public NextAuthMethodBasedMigrationConditionConfig build() {
         return new NextAuthMethodBasedMigrationConditionConfig(this.targetAuthMethod, this.hintPeriod, this.migrationToSameAuthMethodAllowed);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "NextAuthMethodBasedMigrationConditionConfig.NextAuthMethodBasedMigrationConditionConfigBuilder(targetAuthMethod="
            + this.targetAuthMethod
            + ", hintPeriod="
            + this.hintPeriod
            + ", migrationToSameAuthMethodAllowed="
            + this.migrationToSameAuthMethodAllowed
            + ")";
      }
   }
}
