package com.airlock.iam.authentication.domain.service.rememberme;

import com.airlock.iam.authentication.domain.model.rememberme.RememberMeJspTokenHmacKey;
import com.airlock.iam.authentication.domain.model.rememberme.RememberMeJspTokenHmacKeyId;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.api.domain.model.persistency.exception.PersisterException;
import com.airlock.iam.core.misc.persistency.CredentialBean;
import com.airlock.iam.core.misc.persistency.CredentialPersister;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.crypto.MACSigner;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Optional;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

public final class RememberMeJspUserSecretPersisterServiceImpl implements RememberMeJspUserSecretPersisterService {
   private static final ELogger LOG = ELoggerFactory.getLogger(RememberMeJspUserSecretPersisterServiceImpl.class);
   private final CredentialPersister credentialPersister;

   @Override
   public Optional<RememberMeJspTokenHmacKey> findBy(RememberMeJspTokenHmacKeyId keyId) {
      return this.getCurrentSecret(keyId.getId()).map(RememberMeJspTokenHmacKey::rememberMeHmacKey);
   }

   private Optional<byte[]> getCurrentSecret(String username) {
      CredentialBean c;
      try {
         c = this.credentialPersister.getPersistentCredentialByUsername(username);
      } catch (PersisterException e) {
         LOG.info("Error loading JSP Remember-Me secret credential for user " + LogUtil.quote(username) + ": " + e.getMessage());
         return Optional.empty();
      }

      if (c.isReallyActive() && c.hasCurrentData()) {
         String currentSecretB64 = c.getCurrent().getStringData();
         if (StringUtils.isBlank(currentSecretB64)) {
            return Optional.empty();
         } else {
            byte[] secretBytes = Base64.decodeBase64(currentSecretB64);
            if (ArrayUtils.isEmpty(secretBytes)) {
               return Optional.empty();
            } else if (!isRememberMeSecretApplicable(secretBytes)) {
               LOG.debug("Current JSP Remember-Me user secret not applicable for signature algorithm.");
               return Optional.empty();
            } else {
               return Optional.of(secretBytes);
            }
         }
      } else {
         return Optional.empty();
      }
   }

   private static boolean isRememberMeSecretApplicable(byte[] currentSecret) {
      return MACSigner.getCompatibleAlgorithms(currentSecret.length * 8).contains(JWSAlgorithm.parse(RememberMeJspTokenValidator.DEFAULT_ALGORITHM.name()));
   }

   @SuppressFBWarnings(justification = "generated code")
   RememberMeJspUserSecretPersisterServiceImpl(CredentialPersister credentialPersister) {
      this.credentialPersister = credentialPersister;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class RememberMeJspUserSecretPersisterServiceImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private CredentialPersister credentialPersister;

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

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeJspUserSecretPersisterServiceImpl.RememberMeJspUserSecretPersisterServiceImplBuilder credentialPersister(
         CredentialPersister credentialPersister
      ) {
         this.credentialPersister = credentialPersister;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public RememberMeJspUserSecretPersisterServiceImpl build() {
         return new RememberMeJspUserSecretPersisterServiceImpl(this.credentialPersister);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "RememberMeJspUserSecretPersisterServiceImpl.RememberMeJspUserSecretPersisterServiceImplBuilder(credentialPersister="
            + this.credentialPersister
            + ")";
      }
   }
}
