package com.airlock.iam.common.application.configuration.user;

import com.airlock.iam.common.domain.model.user.PersistentUserPredicate;
import com.airlock.iam.common.domain.model.user.UserLockedPredicate;
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.property.RegexProperty;
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.util.Optional;
import java.util.regex.Pattern;

@Plugin(
   description = "Returns true for users who are locked.\nIf configured, the lock date must lie outside the grace period and the lock reason must match the pattern.\n"
)
public class UserLockedPredicateConfig implements PersistentUserPredicateConfig {
   @StringProperty(
      description = "The grace period during which the predicate remains false after a user is locked.\nIf not configured, the grace period is ignored.\nIf configured but no lock date is set on the user (i.e. the corresponding database field is null), the predicate returns false.\n",
      exampleValues = {"90d", "1d 12h"},
      optional = true
   )
   private String lockedGracePeriod;
   private static final String LOCK_DURATION_GRACE_PERIOD_FIELD = "lockedGracePeriod";
   @RegexProperty(
      description = "The lock reason must match this regular expression.\nIf not configured, the lock reason is not checked.\nIf configured but no lock reason is set on the user (i.e. the corresponding database field is null), the predicate returns false.\nThe following are the most frequent lock reasons:\n<ul>\n  <li>LockReason.TooManyLoginFailed</li>\n  <li>LockReason.InitialPasswordExpired</li>\n  <li>LockReason.MaxWrongOldPassword</li>\n  <li>LockReason.InitiatedByUser</li>\n  <li>LockReason.InitiatedByAdmin</li>\n</ul>\n<p>\nNote: Additional custom lock reasons may be present, depending on the IAM configuration.\n</p>\n",
      exampleValues = {"LockReason\\.TooManyLoginFailed", "LockReason.*"},
      optional = true
   )
   private Pattern lockReasonPattern;

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

   @Override
   public PersistentUserPredicate getLogic() {
      return UserLockedPredicate.builder()
         .lockedGracePeriod(Optional.ofNullable(this.lockedGracePeriod).map(duration -> new DurationParser(duration).getDuration()))
         .lockReasonPattern(Optional.ofNullable(this.lockReasonPattern))
         .build();
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public UserLockedPredicateConfig(String lockedGracePeriod, Pattern lockReasonPattern) {
      this.lockedGracePeriod = lockedGracePeriod;
      this.lockReasonPattern = lockReasonPattern;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class UserLockedPredicateConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String lockedGracePeriod;
      @SuppressFBWarnings(justification = "generated code")
      private Pattern lockReasonPattern;

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

      @SuppressFBWarnings(justification = "generated code")
      public UserLockedPredicateConfig.UserLockedPredicateConfigBuilder lockedGracePeriod(String lockedGracePeriod) {
         this.lockedGracePeriod = lockedGracePeriod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserLockedPredicateConfig.UserLockedPredicateConfigBuilder lockReasonPattern(Pattern lockReasonPattern) {
         this.lockReasonPattern = lockReasonPattern;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserLockedPredicateConfig build() {
         return new UserLockedPredicateConfig(this.lockedGracePeriod, this.lockReasonPattern);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "UserLockedPredicateConfig.UserLockedPredicateConfigBuilder(lockedGracePeriod="
            + this.lockedGracePeriod
            + ", lockReasonPattern="
            + this.lockReasonPattern
            + ")";
      }
   }
}
