package com.airlock.iam.oauth2.domain.service.persistence;

import com.airlock.iam.base.misc.log.LogUtil;
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.elog.api.ELogger;
import com.airlock.iam.oauth2.domain.model.token.OAuth2Token;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Date;
import java.util.Optional;
import lombok.NonNull;

public final class OAuth2UserLoader {
   @NonNull
   private final UserStore userStore;
   @NonNull
   private final ELogger logger;

   public Optional<PersistentUser> getValidUser(OAuth2Token token) {
      return this.getUser(token).filter(this::isValidUser);
   }

   public Optional<PersistentUser> getValidUser(String userId) {
      return this.tryFindUser(userId).filter(this::isValidUser);
   }

   private boolean isValidUser(PersistentUser user) {
      String error;
      if (user.isLocked() && !user.getUserValidity().isValidAt(new Date())) {
         error = "locked and invalid";
      } else if (user.isLocked()) {
         error = "locked";
      } else {
         if (user.getUserValidity().isValidAt(new Date())) {
            return true;
         }

         error = "invalid";
      }

      this.logger.info(String.format("Invalid OAuth 2.0 request. User %s is %s.", LogUtil.quote(user.getName()), error));
      return false;
   }

   public Optional<PersistentUser> getUser(OAuth2Token token) {
      return this.tryFindUser(token.getUserId().getValue());
   }

   private Optional<PersistentUser> tryFindUser(String assignedTokenUser) {
      return this.userStore.findByIdentity(assignedTokenUser);
   }

   @SuppressFBWarnings(justification = "generated code")
   public OAuth2UserLoader(@NonNull UserStore userStore, @NonNull ELogger logger) {
      if (userStore == null) {
         throw new NullPointerException("userStore is marked non-null but is null");
      }

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

      this.userStore = userStore;
      this.logger = logger;
   }
}
