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

import com.airlock.iam.common.api.domain.model.user.PersistentUser;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.Optional;
import java.util.regex.Pattern;
import lombok.NonNull;

public final class UserLockedPredicate implements PersistentUserPredicate {
   @NonNull
   private final Optional<Duration> lockedGracePeriod;
   @NonNull
   private final Optional<Pattern> lockReasonPattern;

   @Override
   public boolean evaluate(PersistentUser user) {
      if (!user.isLocked()) {
         return false;
      }

      Boolean userWasLockedLongEnough = this.lockedGracePeriod
         .<Boolean>map(gracePeriod -> userWasLockedLongEnough(user.getLockDate(), gracePeriod))
         .orElse(true);
      Boolean lockReasonMatchesPattern = this.lockReasonPattern.<Boolean>map(pattern -> lockReasonMatchesPattern(user.getLockReason(), pattern)).orElse(true);
      return userWasLockedLongEnough && lockReasonMatchesPattern;
   }

   private static boolean lockReasonMatchesPattern(String lockReason, Pattern pattern) {
      return lockReason == null ? false : pattern.matcher(lockReason).matches();
   }

   private static boolean userWasLockedLongEnough(Date lockDate, Duration gracePeriod) {
      if (lockDate == null) {
         return false;
      }

      Instant gracePeriodEnd = lockDate.toInstant().plus(gracePeriod);
      return Instant.now().isAfter(gracePeriodEnd);
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public UserLockedPredicate(@NonNull Optional<Duration> lockedGracePeriod, @NonNull Optional<Pattern> lockReasonPattern) {
      if (lockedGracePeriod == null) {
         throw new NullPointerException("lockedGracePeriod is marked non-null but is null");
      }

      if (lockReasonPattern == null) {
         throw new NullPointerException("lockReasonPattern is marked non-null but is null");
      }

      this.lockedGracePeriod = lockedGracePeriod;
      this.lockReasonPattern = lockReasonPattern;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class UserLockedPredicateBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Optional<Duration> lockedGracePeriod;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<Pattern> lockReasonPattern;

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

      @SuppressFBWarnings(justification = "generated code")
      public UserLockedPredicate.UserLockedPredicateBuilder lockedGracePeriod(@NonNull Optional<Duration> lockedGracePeriod) {
         if (lockedGracePeriod == null) {
            throw new NullPointerException("lockedGracePeriod is marked non-null but is null");
         }

         this.lockedGracePeriod = lockedGracePeriod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserLockedPredicate.UserLockedPredicateBuilder lockReasonPattern(@NonNull Optional<Pattern> lockReasonPattern) {
         if (lockReasonPattern == null) {
            throw new NullPointerException("lockReasonPattern is marked non-null but is null");
         }

         this.lockReasonPattern = lockReasonPattern;
         return this;
      }

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

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