package com.airlock.iam.flow.shared.application.service.validation;

import com.airlock.iam.base.api.domain.model.email.EmailAddress;
import com.airlock.iam.base.api.domain.model.validation.GenericError;
import com.airlock.iam.base.api.domain.model.validation.ValidationResult;
import com.airlock.iam.base.api.domain.model.validation.ValidatorError;
import com.airlock.iam.common.api.domain.model.user.User;
import com.airlock.iam.common.domain.service.user.StringValueUniquenessService;
import com.airlock.iam.flow.shared.api.domain.model.validation.UniquenessValidationService;
import com.airlock.iam.flow.shared.domain.model.step.email.EmailChangeDescription;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.inject.Inject;
import java.util.Optional;

public final class EmailChangeUniquenessValidationService implements UniquenessValidationService {
   private final EmailChangeUniquenessValidationService.EmailChangeUniquenessValidationServiceSettings settings;
   private final StringValueUniquenessService uniquenessService;
   private final EmailChangeDescription changeDescription;

   @Inject
   public EmailChangeUniquenessValidationService(
      EmailChangeUniquenessValidationService.EmailChangeUniquenessValidationServiceSettings settings,
      StringValueUniquenessService uniquenessService,
      EmailChangeDescription changeDescription
   ) {
      this.settings = settings;
      this.uniquenessService = uniquenessService;
      this.changeDescription = changeDescription;
   }

   @Override
   public ValidationResult validateUniqueness(User user, UniquenessValidationService.ValidationMode mode) {
      if (mode == UniquenessValidationService.ValidationMode.REPORT_CONSIDERING_STEALTH) {
         return ValidationResult.valid();
      } else {
         return this.isEmailAddressAttributeUnique(user)
            ? ValidationResult.valid()
            : ValidationResult.invalid(ValidatorError.validatorError(this.settings.getUserAttributeName(), GenericError.NOT_UNIQUE));
      }
   }

   private boolean isEmailAddressAttributeUnique(User user) {
      return this.changeDescription.getEmailAddress().map(change -> this.isAddressUnique(user, change)).orElse(true);
   }

   private boolean isAddressUnique(User user, EmailAddress change) {
      return this.uniquenessService.attributeOfUserIsUnique(this.settings.getUserAttributeName(), change.value(), Optional.of(user.getName()));
   }

   public static final class EmailChangeUniquenessValidationServiceSettings {
      private final String userAttributeName;

      @SuppressFBWarnings(justification = "generated code")
      public EmailChangeUniquenessValidationServiceSettings(String userAttributeName) {
         this.userAttributeName = userAttributeName;
      }

      @SuppressFBWarnings(justification = "generated code")
      public String getUserAttributeName() {
         return this.userAttributeName;
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public boolean equals(Object o) {
         if (o == this) {
            return true;
         } else if (!(o instanceof EmailChangeUniquenessValidationService.EmailChangeUniquenessValidationServiceSettings other)) {
            return false;
         } else {
            Object this$userAttributeName = this.userAttributeName;
            Object other$userAttributeName = other.userAttributeName;
            return this$userAttributeName == null ? other$userAttributeName == null : this$userAttributeName.equals(other$userAttributeName);
         }
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public int hashCode() {
         int PRIME = 59;
         int result = 1;
         Object $userAttributeName = this.userAttributeName;
         return result * 59 + ($userAttributeName == null ? 43 : $userAttributeName.hashCode());
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "EmailChangeUniquenessValidationService.EmailChangeUniquenessValidationServiceSettings(userAttributeName=" + this.getUserAttributeName() + ")";
      }
   }
}
