package com.airlock.iam.admin.application.service.user;

import com.airlock.iam.base.api.domain.model.validation.ValidationResult;
import com.airlock.iam.base.api.domain.model.validation.Validator;
import com.airlock.iam.base.misc.time.TimeProvider;
import com.airlock.iam.common.api.domain.model.store.user.UserStore;
import com.airlock.iam.common.api.domain.model.user.PersistentUser;
import com.airlock.iam.common.api.domain.model.user.validity.UserValidity;
import com.airlock.iam.common.api.domain.model.user.validity.UserValidityPeriod;
import com.airlock.iam.common.application.service.validation.DateRangeValidator;
import com.airlock.iam.core.misc.util.DateRange;
import com.airlock.iam.log.api.signing.SigningLogger;
import com.google.common.base.Preconditions;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import java.util.Date;

public class UserValidityService {
   private final UserStore userStore;
   private final TimeProvider timeProvider;
   private final SigningLogger signingLogger;

   @Inject
   public UserValidityService(@Named("MANAGED_USERS_STORE") UserStore userStore, TimeProvider timeProvider, SigningLogger logger) {
      this.userStore = userStore;
      this.timeProvider = timeProvider;
      this.signingLogger = logger;
   }

   public boolean isValidNow(String userId) {
      return this.getUserValidity(userId).isValidAt(this.timeProvider.getCurrentTime());
   }

   public UserValidity getUserValidity(String userId) {
      Preconditions.checkNotNull(userId);
      PersistentUser user = (PersistentUser)this.userStore.getByIdentity(userId);
      return user.getUserValidity();
   }

   public void setValidBetween(String userId, Date beginDate, Date endDate) {
      Preconditions.checkNotNull(userId);
      Preconditions.checkNotNull(beginDate);
      Preconditions.checkNotNull(endDate);
      PersistentUser user = (PersistentUser)this.userStore.getByIdentity(userId);
      user.setUserValidity(user.getUserValidity().withUserValidityPeriod(UserValidityPeriod.validBetween(beginDate, endDate)));
      this.userStore.update(user);
      this.signingLogger.log("set user \"%s\" to be valid from %tF until %tF", new Object[]{userId, beginDate, endDate});
   }

   public void setNullableValidityPeriod(String userId, @Nullable Date beginDate, @Nullable Date endDate) {
      Preconditions.checkNotNull(userId);
      PersistentUser user = (PersistentUser)this.userStore.getByIdentity(userId);
      UserValidity oldValidity = user.getUserValidity();
      user.setUserValidity(oldValidity.withUserValidityPeriod(UserValidityPeriod.create(beginDate, endDate)));
      this.userStore.update(user);
      this.signingLogger.log("set user \"%s\" to be valid from %tF until %tF", new Object[]{userId, beginDate, endDate});
   }

   public ValidationResult validate(@Nullable Date beginDate, @Nullable Date endDate) {
      Validator<DateRange> validator = DateRangeValidator.builder().mandatoryFrom(false).mandatoryTo(false).fromFieldName("from").toFieldName("until").build();
      return validator.validate(DateRange.of(beginDate, endDate));
   }

   public void enable(String userId) {
      Preconditions.checkNotNull(userId);
      PersistentUser user = (PersistentUser)this.userStore.getByIdentity(userId);
      UserValidity userValidity = user.getUserValidity().withUserEnabled();
      user.setUserValidity(userValidity);
      this.userStore.update(user);
      this.signingLogger.log("enabled user \"%s\"", new Object[]{userId});
   }

   public void disable(String userId) {
      Preconditions.checkNotNull(userId);
      PersistentUser user = (PersistentUser)this.userStore.getByIdentity(userId);
      UserValidity userValidity = user.getUserValidity().withUserDisabled();
      user.setUserValidity(userValidity);
      this.userStore.update(user);
      this.signingLogger.log("disabled user \"%s\"", new Object[]{userId});
   }

   public boolean isEnabled(String userId) {
      return this.getUserValidity(userId).isUserEnabled();
   }

   public void setValidFrom(String userId, Date date) {
      Preconditions.checkNotNull(userId);
      Preconditions.checkNotNull(date);
      PersistentUser user = (PersistentUser)this.userStore.getByIdentity(userId);
      UserValidityPeriod oldPeriod = user.getUserValidity().getUserValidityPeriod();
      user.setUserValidity(user.getUserValidity().withUserValidityPeriod(oldPeriod.withValidityFrom(date)));
      this.userStore.update(user);
      this.signingLogger.log("set user \"%s\" to be valid from %tF", new Object[]{userId, date});
   }

   public void resetValidFrom(String userId) {
      Preconditions.checkNotNull(userId);
      PersistentUser user = (PersistentUser)this.userStore.getByIdentity(userId);
      UserValidityPeriod oldPeriod = user.getUserValidity().getUserValidityPeriod();
      user.setUserValidity(user.getUserValidity().withUserValidityPeriod(oldPeriod.withoutValidityFrom()));
      this.userStore.update(user);
      this.signingLogger.log("reset date from which on user \"%s\" is valid", new Object[]{userId});
   }

   public void setValidUntil(String userId, Date date) {
      Preconditions.checkNotNull(userId);
      Preconditions.checkNotNull(date);
      PersistentUser user = (PersistentUser)this.userStore.getByIdentity(userId);
      UserValidityPeriod oldPeriod = user.getUserValidity().getUserValidityPeriod();
      user.setUserValidity(user.getUserValidity().withUserValidityPeriod(oldPeriod.withValidityUntil(date)));
      this.signingLogger.log("set user \"%s\" to be valid until %tF", new Object[]{userId, date});
      this.userStore.update(user);
   }

   public void resetValidUntil(String userId) {
      Preconditions.checkNotNull(userId);
      PersistentUser user = (PersistentUser)this.userStore.getByIdentity(userId);
      UserValidityPeriod oldPeriod = user.getUserValidity().getUserValidityPeriod();
      user.setUserValidity(user.getUserValidity().withUserValidityPeriod(oldPeriod.withoutValidityUntil()));
      this.userStore.update(user);
      this.signingLogger.log("reset date until user \"%s\" is valid", new Object[]{userId});
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class UserValidityServiceBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private UserStore userStore;
      @SuppressFBWarnings(justification = "generated code")
      private TimeProvider timeProvider;
      @SuppressFBWarnings(justification = "generated code")
      private SigningLogger signingLogger;

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

      @SuppressFBWarnings(justification = "generated code")
      public UserValidityService.UserValidityServiceBuilder userStore(UserStore userStore) {
         this.userStore = userStore;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserValidityService.UserValidityServiceBuilder timeProvider(TimeProvider timeProvider) {
         this.timeProvider = timeProvider;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserValidityService.UserValidityServiceBuilder signingLogger(SigningLogger signingLogger) {
         this.signingLogger = signingLogger;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserValidityService build() {
         return new UserValidityService(this.userStore, this.timeProvider, this.signingLogger);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "UserValidityService.UserValidityServiceBuilder(userStore="
            + this.userStore
            + ", timeProvider="
            + this.timeProvider
            + ", signingLogger="
            + this.signingLogger
            + ")";
      }
   }
}
