package com.airlock.iam.factor.domain.model.airlock2fa;

import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
import java.util.Optional;
import lombok.NonNull;

public class Airlock2FAUserAttributes {
   @NonNull
   private final Optional<String> displayName;
   @NonNull
   private final Date createdAt;
   @NonNull
   private final Date updatedAt;
   private final int failedAttempts;
   private final int maxFailedAttempts;
   @NonNull
   private final Airlock2FAFactorSet allowedFactors;
   private Optional<Airlock2FAAccountStatus> status;

   public boolean isLocked() {
      return this.status.<Boolean>map(s -> s == Airlock2FAAccountStatus.LOCKED).orElse(false);
   }

   public boolean isEnabled() {
      return this.status.<Boolean>map(s -> s == Airlock2FAAccountStatus.ENABLED || s == Airlock2FAAccountStatus.ENABLED_WITH_BYPASS).orElse(false);
   }

   public boolean isDisabled() {
      return this.status.<Boolean>map(s -> s == Airlock2FAAccountStatus.DISABLED || s == Airlock2FAAccountStatus.PERMANENTLY_DISABLED).orElse(false);
   }

   public boolean isPermanentlyDisabled() {
      return this.status.<Boolean>map(s -> s == Airlock2FAAccountStatus.PERMANENTLY_DISABLED).orElse(false);
   }

   public void lock() {
      if (this.isDisabled()) {
         throw new ViolationException("Cannot lock Airlock 2FA account in disabled state.");
      }

      this.status = Optional.of(Airlock2FAAccountStatus.LOCKED);
   }

   public void unlock() {
      if (this.isDisabled()) {
         throw new ViolationException("Cannot unlock Airlock 2FA account in disabled state.");
      }

      this.status = Optional.empty();
   }

   public boolean hasStatus(Airlock2FAAccountStatus accountStatus) {
      return this.status.isPresent() && this.status.get() == accountStatus;
   }

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

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   public Optional<String> getDisplayName() {
      return this.displayName;
   }

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   public Date getCreatedAt() {
      return this.createdAt;
   }

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   public Date getUpdatedAt() {
      return this.updatedAt;
   }

   @SuppressFBWarnings(justification = "generated code")
   public int getFailedAttempts() {
      return this.failedAttempts;
   }

   @SuppressFBWarnings(justification = "generated code")
   public int getMaxFailedAttempts() {
      return this.maxFailedAttempts;
   }

   @NonNull
   @SuppressFBWarnings(justification = "generated code")
   public Airlock2FAFactorSet getAllowedFactors() {
      return this.allowedFactors;
   }

   @SuppressFBWarnings(justification = "generated code")
   public Optional<Airlock2FAAccountStatus> getStatus() {
      return this.status;
   }

   @SuppressFBWarnings(justification = "generated code")
   private Airlock2FAUserAttributes(
      @NonNull Optional<String> displayName,
      @NonNull Date createdAt,
      @NonNull Date updatedAt,
      int failedAttempts,
      int maxFailedAttempts,
      @NonNull Airlock2FAFactorSet allowedFactors,
      Optional<Airlock2FAAccountStatus> status
   ) {
      if (displayName == null) {
         throw new NullPointerException("displayName is marked non-null but is null");
      }

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

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

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

      this.displayName = displayName;
      this.createdAt = createdAt;
      this.updatedAt = updatedAt;
      this.failedAttempts = failedAttempts;
      this.maxFailedAttempts = maxFailedAttempts;
      this.allowedFactors = allowedFactors;
      this.status = status;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class Airlock2FAUserAttributesBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Optional<String> displayName;
      @SuppressFBWarnings(justification = "generated code")
      private Date createdAt;
      @SuppressFBWarnings(justification = "generated code")
      private Date updatedAt;
      @SuppressFBWarnings(justification = "generated code")
      private int failedAttempts;
      @SuppressFBWarnings(justification = "generated code")
      private int maxFailedAttempts;
      @SuppressFBWarnings(justification = "generated code")
      private Airlock2FAFactorSet allowedFactors;
      @SuppressFBWarnings(justification = "generated code")
      private Optional<Airlock2FAAccountStatus> status;

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

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUserAttributes.Airlock2FAUserAttributesBuilder displayName(@NonNull Optional<String> displayName) {
         if (displayName == null) {
            throw new NullPointerException("displayName is marked non-null but is null");
         }

         this.displayName = displayName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUserAttributes.Airlock2FAUserAttributesBuilder createdAt(@NonNull Date createdAt) {
         if (createdAt == null) {
            throw new NullPointerException("createdAt is marked non-null but is null");
         }

         this.createdAt = createdAt;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUserAttributes.Airlock2FAUserAttributesBuilder updatedAt(@NonNull Date updatedAt) {
         if (updatedAt == null) {
            throw new NullPointerException("updatedAt is marked non-null but is null");
         }

         this.updatedAt = updatedAt;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUserAttributes.Airlock2FAUserAttributesBuilder failedAttempts(int failedAttempts) {
         this.failedAttempts = failedAttempts;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUserAttributes.Airlock2FAUserAttributesBuilder maxFailedAttempts(int maxFailedAttempts) {
         this.maxFailedAttempts = maxFailedAttempts;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUserAttributes.Airlock2FAUserAttributesBuilder allowedFactors(@NonNull Airlock2FAFactorSet allowedFactors) {
         if (allowedFactors == null) {
            throw new NullPointerException("allowedFactors is marked non-null but is null");
         }

         this.allowedFactors = allowedFactors;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUserAttributes.Airlock2FAUserAttributesBuilder status(Optional<Airlock2FAAccountStatus> status) {
         this.status = status;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public Airlock2FAUserAttributes build() {
         return new Airlock2FAUserAttributes(
            this.displayName, this.createdAt, this.updatedAt, this.failedAttempts, this.maxFailedAttempts, this.allowedFactors, this.status
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "Airlock2FAUserAttributes.Airlock2FAUserAttributesBuilder(displayName="
            + this.displayName
            + ", createdAt="
            + this.createdAt
            + ", updatedAt="
            + this.updatedAt
            + ", failedAttempts="
            + this.failedAttempts
            + ", maxFailedAttempts="
            + this.maxFailedAttempts
            + ", allowedFactors="
            + this.allowedFactors
            + ", status="
            + this.status
            + ")";
      }
   }
}
