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

import com.airlock.iam.common.application.configuration.user.UserProfileValueProviderConfig;
import com.airlock.iam.common.domain.model.user.profileitems.ExtendedStringProfileItemLogic;
import com.airlock.iam.core.misc.persistency.UserIterator;
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.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.exception.PropertyTypeMismatchException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.regex.Pattern;

@Plugin(
   description = "Extension to the string user profile item. Using regular expressions, the display value can be inferred from the actual value and if the field is modifiable can also be determined using a regular expression."
)
public class ExtendedStringUserProfileItemConfig extends StringUserProfileItemConfig {
   @RegexProperty(
      description = "<p>This regular expression is used to extract values which can be used in \"Display Output\" to determine the display value.</p> <p>The two fields are applied to the value to be displayed as follows: <code>value.replaceAll(displayPattern, displayReplacement)</code>.</p>For example, a displayPattern of \".*CN=([^,]*).*\" and displayReplacement of \"Name: $1\" would transform the value \"C=CH, L=Zurich, CN=Ergon Informatik AG\" to \"Name: Ergon Informatik AG\".</p>",
      optional = true,
      matchAgainstWholeInput = false,
      exampleValues = ".*CN=([^,]*).*"
   )
   private Pattern displayPattern;
   @StringProperty(
      description = "The output string produced using the \"Display Pattern\". See that description for detailed information about the display string transformation.",
      optional = true
   )
   private String displayReplacement;
   @RegexProperty(
      description = "This regular expression is used to determine if the value is modifiable for the user or read-only. If this pattern is defined, the \"Modifiable\" flag is overwritten and determined based on the value to be displayed: if the pattern matches the entered value, then it is not editable by the user. If the pattern is not defined, then the \"Modifiable\" flag is used.",
      optional = true,
      exampleValues = "[^@]*@ergon.ch"
   )
   private Pattern readOnlyPattern;

   public ExtendedStringUserProfileItemConfig(
      String stringResourceKey,
      String propertyName,
      boolean optional,
      boolean modifiable,
      boolean validateOnlyChangedValues,
      boolean sortable,
      Pattern validationPattern,
      UserIterator checkUniqueness,
      boolean checkUniquenessAgainstUsername,
      UserProfileValueProviderConfig prefill,
      Pattern displayPattern,
      String displayReplacement,
      Pattern readOnlyPattern
   ) {
      super(
         stringResourceKey,
         propertyName,
         optional,
         modifiable,
         validateOnlyChangedValues,
         sortable,
         validationPattern,
         checkUniqueness,
         checkUniquenessAgainstUsername,
         prefill
      );
      this.displayPattern = displayPattern;
      this.displayReplacement = displayReplacement;
      this.readOnlyPattern = readOnlyPattern;
   }

   @ConfigurationValidator
   public static void ensureBothDisplayTransformersConfigured(
      PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws PropertyConstraintViolationException, PropertyTypeMismatchException {
      String pat = pc.getSimplePropertyConfigurationValue("displayPattern", env, context);
      String out = pc.getSimplePropertyConfigurationValue("displayReplacement", env, context);
      if (pat == null ^ out == null) {
         throw new PropertyConstraintViolationException(
            "displayPattern", pc, env, context, "\"displayPattern\" and \"displayReplacement\" can only be configured together."
         );
      }
   }

   public ExtendedStringProfileItemLogic getProfileItemLogic() {
      return ExtendedStringProfileItemLogic.subbuilder()
         .checkUniquenessAgainstUsername(this.isCheckUniquenessAgainstUsername())
         .optional(this.isOptional())
         .modifiable(this.isModifiable())
         .propertyName(this.getPropertyName())
         .uniquenessChecker(this.getCheckUniqueness())
         .validateOnlyChangedValues(this.isValidateOnlyChangedValues())
         .validationPattern(this.getValidationPattern())
         .displayPattern(this.displayPattern)
         .displayReplacement(this.displayReplacement)
         .readOnlyPattern(this.readOnlyPattern)
         .build();
   }

   @SuppressFBWarnings(justification = "generated code")
   public static ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder extendedStringUserProfileItemConfigBuilder() {
      return new ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder();
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public ExtendedStringUserProfileItemConfig(Pattern displayPattern, String displayReplacement, Pattern readOnlyPattern) {
      this.displayPattern = displayPattern;
      this.displayReplacement = displayReplacement;
      this.readOnlyPattern = readOnlyPattern;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class ExtendedStringUserProfileItemConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String stringResourceKey;
      @SuppressFBWarnings(justification = "generated code")
      private String propertyName;
      @SuppressFBWarnings(justification = "generated code")
      private boolean optional;
      @SuppressFBWarnings(justification = "generated code")
      private boolean modifiable;
      @SuppressFBWarnings(justification = "generated code")
      private boolean validateOnlyChangedValues;
      @SuppressFBWarnings(justification = "generated code")
      private boolean sortable;
      @SuppressFBWarnings(justification = "generated code")
      private Pattern validationPattern;
      @SuppressFBWarnings(justification = "generated code")
      private UserIterator checkUniqueness;
      @SuppressFBWarnings(justification = "generated code")
      private boolean checkUniquenessAgainstUsername;
      @SuppressFBWarnings(justification = "generated code")
      private UserProfileValueProviderConfig prefill;
      @SuppressFBWarnings(justification = "generated code")
      private Pattern displayPattern;
      @SuppressFBWarnings(justification = "generated code")
      private String displayReplacement;
      @SuppressFBWarnings(justification = "generated code")
      private Pattern readOnlyPattern;

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

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder stringResourceKey(String stringResourceKey) {
         this.stringResourceKey = stringResourceKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder propertyName(String propertyName) {
         this.propertyName = propertyName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder optional(boolean optional) {
         this.optional = optional;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder modifiable(boolean modifiable) {
         this.modifiable = modifiable;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder validateOnlyChangedValues(boolean validateOnlyChangedValues) {
         this.validateOnlyChangedValues = validateOnlyChangedValues;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder sortable(boolean sortable) {
         this.sortable = sortable;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder validationPattern(Pattern validationPattern) {
         this.validationPattern = validationPattern;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder checkUniqueness(UserIterator checkUniqueness) {
         this.checkUniqueness = checkUniqueness;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder checkUniquenessAgainstUsername(
         boolean checkUniquenessAgainstUsername
      ) {
         this.checkUniquenessAgainstUsername = checkUniquenessAgainstUsername;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder prefill(UserProfileValueProviderConfig prefill) {
         this.prefill = prefill;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder displayPattern(Pattern displayPattern) {
         this.displayPattern = displayPattern;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder displayReplacement(String displayReplacement) {
         this.displayReplacement = displayReplacement;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder readOnlyPattern(Pattern readOnlyPattern) {
         this.readOnlyPattern = readOnlyPattern;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExtendedStringUserProfileItemConfig build() {
         return new ExtendedStringUserProfileItemConfig(
            this.stringResourceKey,
            this.propertyName,
            this.optional,
            this.modifiable,
            this.validateOnlyChangedValues,
            this.sortable,
            this.validationPattern,
            this.checkUniqueness,
            this.checkUniquenessAgainstUsername,
            this.prefill,
            this.displayPattern,
            this.displayReplacement,
            this.readOnlyPattern
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "ExtendedStringUserProfileItemConfig.ExtendedStringUserProfileItemConfigBuilder(stringResourceKey="
            + this.stringResourceKey
            + ", propertyName="
            + this.propertyName
            + ", optional="
            + this.optional
            + ", modifiable="
            + this.modifiable
            + ", validateOnlyChangedValues="
            + this.validateOnlyChangedValues
            + ", sortable="
            + this.sortable
            + ", validationPattern="
            + this.validationPattern
            + ", checkUniqueness="
            + this.checkUniqueness
            + ", checkUniquenessAgainstUsername="
            + this.checkUniquenessAgainstUsername
            + ", prefill="
            + this.prefill
            + ", displayPattern="
            + this.displayPattern
            + ", displayReplacement="
            + this.displayReplacement
            + ", readOnlyPattern="
            + this.readOnlyPattern
            + ")";
      }
   }
}
