package com.airlock.iam.common.domain.model.user.profileitems;

import com.airlock.iam.base.api.domain.model.store.exception.StoreFailureException;
import com.airlock.iam.common.api.domain.model.persistency.exception.PersisterException;
import com.airlock.iam.core.misc.persistency.SearchStrategy;
import com.airlock.iam.core.misc.persistency.UserIterator;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;

public class StringProfileItemLogic implements UserProfileItemLogic {
   private final boolean validateOnlyChangedValues;
   private final String propertyName;
   private final boolean optional;
   private final boolean modifiable;
   private final Pattern validationPattern;
   private final UserIterator uniquenessChecker;
   private final boolean checkUniquenessAgainstUsername;
   private final boolean emailAddress;

   @Override
   public UserProfileItemLogic.CheckResult validate(Object newValue, Object oldValue, String uid) {
      if (UserProfileItemLogic.validationRequired(newValue, oldValue, this.validateOnlyChangedValues)) {
         String strValue = Objects.toString(newValue, "");
         if (StringUtils.isBlank(strValue)) {
            if (!this.optional) {
               return UserProfileItemLogic.CheckResult.REQUIRED;
            }
         } else if (this.validationPattern != null && !this.validationPattern.matcher(strValue).matches()) {
            return UserProfileItemLogic.CheckResult.WRONG_FORMAT;
         }

         if (this.uniquenessChecker != null && this.isValueNotUnique(strValue, uid)) {
            return UserProfileItemLogic.CheckResult.NOT_UNIQUE;
         }
      }

      return UserProfileItemLogic.CheckResult.IS_OK;
   }

   private boolean isValueNotUnique(String strValue, String uid) {
      if (!StringUtils.isBlank(strValue) && this.uniquenessChecker != null) {
         try {
            List<String> matchingUserNames = this.uniquenessChecker
               .getMatchingUserIds(new String[]{this.propertyName}, strValue, SearchStrategy.EXACT, this.checkUniquenessAgainstUsername);
            if (matchingUserNames.isEmpty()) {
               return false;
            } else {
               return uid == null ? true : matchingUserNames.size() > 1 || !matchingUserNames.getFirst().equals(uid);
            }
         } catch (PersisterException e) {
            throw new StoreFailureException("Error searching users for uniqueness check: " + e.getMessage(), e);
         }
      } else {
         return false;
      }
   }

   public String formatForPersistence(Object value) {
      return StringUtils.trimToEmpty(Objects.toString(value, ""));
   }

   @Override
   public Object transformPersistentValue(Object value) {
      return Objects.toString(value, null);
   }

   @Override
   public boolean isModifiable(Object value) {
      return this.modifiable;
   }

   @SuppressFBWarnings(justification = "generated code")
   StringProfileItemLogic(
      boolean validateOnlyChangedValues,
      String propertyName,
      boolean optional,
      boolean modifiable,
      Pattern validationPattern,
      UserIterator uniquenessChecker,
      boolean checkUniquenessAgainstUsername,
      boolean emailAddress
   ) {
      this.validateOnlyChangedValues = validateOnlyChangedValues;
      this.propertyName = propertyName;
      this.optional = optional;
      this.modifiable = modifiable;
      this.validationPattern = validationPattern;
      this.uniquenessChecker = uniquenessChecker;
      this.checkUniquenessAgainstUsername = checkUniquenessAgainstUsername;
      this.emailAddress = emailAddress;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public StringProfileItemLogic.StringProfileItemLogicBuilder toBuilder() {
      return new StringProfileItemLogic.StringProfileItemLogicBuilder()
         .validateOnlyChangedValues(this.validateOnlyChangedValues)
         .propertyName(this.propertyName)
         .optional(this.optional)
         .modifiable(this.modifiable)
         .validationPattern(this.validationPattern)
         .uniquenessChecker(this.uniquenessChecker)
         .checkUniquenessAgainstUsername(this.checkUniquenessAgainstUsername)
         .emailAddress(this.emailAddress);
   }

   @SuppressFBWarnings(justification = "generated code")
   public boolean isEmailAddress() {
      return this.emailAddress;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class StringProfileItemLogicBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private boolean validateOnlyChangedValues;
      @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 Pattern validationPattern;
      @SuppressFBWarnings(justification = "generated code")
      private UserIterator uniquenessChecker;
      @SuppressFBWarnings(justification = "generated code")
      private boolean checkUniquenessAgainstUsername;
      @SuppressFBWarnings(justification = "generated code")
      private boolean emailAddress;

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

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public StringProfileItemLogic.StringProfileItemLogicBuilder uniquenessChecker(UserIterator uniquenessChecker) {
         this.uniquenessChecker = uniquenessChecker;
         return this;
      }

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

      @SuppressFBWarnings(justification = "generated code")
      public StringProfileItemLogic.StringProfileItemLogicBuilder emailAddress(boolean emailAddress) {
         this.emailAddress = emailAddress;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public StringProfileItemLogic build() {
         return new StringProfileItemLogic(
            this.validateOnlyChangedValues,
            this.propertyName,
            this.optional,
            this.modifiable,
            this.validationPattern,
            this.uniquenessChecker,
            this.checkUniquenessAgainstUsername,
            this.emailAddress
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "StringProfileItemLogic.StringProfileItemLogicBuilder(validateOnlyChangedValues="
            + this.validateOnlyChangedValues
            + ", propertyName="
            + this.propertyName
            + ", optional="
            + this.optional
            + ", modifiable="
            + this.modifiable
            + ", validationPattern="
            + this.validationPattern
            + ", uniquenessChecker="
            + this.uniquenessChecker
            + ", checkUniquenessAgainstUsername="
            + this.checkUniquenessAgainstUsername
            + ", emailAddress="
            + this.emailAddress
            + ")";
      }
   }
}
