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;
import java.util.Optional;

@Plugin(
   description = "Flow migration condition that is fulfilled if:\n<ul><li>the user has no migration date set and the feature \"Never Migrate\" is enabled.</li>\n<li>the features \"Never Migrate\" and \"Never Migrate with to Date\" are enabled and the\nmigration date is within or after the \"Never Migrate Period Days\".</li></ul>",
   displayName = "Never Migrate Possible"
)
public final class NeverMigrateConditionConfig implements FlowConditionConfig {
   @BooleanProperty(
      description = "Enables the feature \"Never Migrate\" even if there is a migration date set for the corresponding user.\n<p>Whether it is possible to \"Never Migrate\" depends on whether or not a migration date is set and whether\nthe authentication is happening during the \"Never Migrate Period\" (if set at all).</p>",
      optional = true,
      defaultValue = "false",
      displayName = "Enable \"Never Migrate\" Despite Migration Date"
   )
   private boolean neverMigratePossibleWithToDate;
   @StringProperty(
      description = "<p>Defines the period before the migration date in which the feature \"Never Migrate\" is active.</p>\nPrerequisites for this property to take effect:\n<ul><li>A migration date must be set.</li>\n<li>The \"Never Migrate\" feature must be enabled.</li>\n<li>The feature \"Never Migrate Despite Migration Date\" must be enabled.</li>\n<li>A \"Hint Period\" must be specified.</li></ul>\n<p>If this property is not set, the feature \"Never Migrate\" is possible during and after the entire \"Hint Period\" if the\"Never Migrate\" feature is enabled.</p>\n<p>The value of this property must be smaller or equal \"Hint Period Days\".</p>\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>",
      optional = true,
      exampleValues = {"7d", "30d", "14d 6h 30m"},
      displayName = "Never Migrate Period"
   )
   private String neverMigratePeriod;
   private static final String NEVER_MIGRATE_PERIOD_PROPERTY = "neverMigratePeriod";
   private Optional<Duration> neverMigratePeriodDuration;

   private NeverMigrateConditionConfig(boolean neverMigratePossibleWithToDate, String neverMigratePeriod) {
      this.neverMigratePossibleWithToDate = neverMigratePossibleWithToDate;
      this.neverMigratePeriod = neverMigratePeriod;
   }

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

   @AfterConfigActivation
   void parseNeverMigrateDuration() {
      this.neverMigratePeriodDuration = Optional.ofNullable(this.neverMigratePeriod).map(d -> new DurationParser(d).getDuration());
   }

   public boolean isNeverMigratePossibleWithToDate() {
      return this.neverMigratePossibleWithToDate;
   }

   public String getNeverMigratePeriod() {
      return this.neverMigratePeriod;
   }

   public Optional<Duration> getNeverMigratePeriodDuration() {
      return this.neverMigratePeriodDuration;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class NeverMigrateConditionConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private boolean neverMigratePossibleWithToDate;
      @SuppressFBWarnings(justification = "generated code")
      private String neverMigratePeriod;

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

      @SuppressFBWarnings(justification = "generated code")
      public NeverMigrateConditionConfig.NeverMigrateConditionConfigBuilder neverMigratePossibleWithToDate(boolean neverMigratePossibleWithToDate) {
         this.neverMigratePossibleWithToDate = neverMigratePossibleWithToDate;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public NeverMigrateConditionConfig.NeverMigrateConditionConfigBuilder neverMigratePeriod(String neverMigratePeriod) {
         this.neverMigratePeriod = neverMigratePeriod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public NeverMigrateConditionConfig build() {
         return new NeverMigrateConditionConfig(this.neverMigratePossibleWithToDate, this.neverMigratePeriod);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "NeverMigrateConditionConfig.NeverMigrateConditionConfigBuilder(neverMigratePossibleWithToDate="
            + this.neverMigratePossibleWithToDate
            + ", neverMigratePeriod="
            + this.neverMigratePeriod
            + ")";
      }
   }
}
