package com.airlock.iam.flow.shared.domain.model.rememberme;

import com.airlock.iam.base.misc.util.Base64Util;
import com.airlock.iam.common.api.domain.model.binary.ByteSequence;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.security.util.SeededSecureRandom;
import jakarta.annotation.Nullable;
import java.util.Optional;
import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

public record RememberMeSecret(ByteSequence secret) {
   private static final ELogger LOG = ELoggerFactory.getLogger(RememberMeSecret.class);
   static final int NUMBER_OF_BYTES = 150;

   public RememberMeSecret {
      Validate.isTrue(secret.bytes().length == 150, String.format("Expected %d bytes, but got %d", 150, secret.bytes().length), new Object[0]);
   }

   public static RememberMeSecret rememberMeSecret(byte[] bytes) {
      return new RememberMeSecret(ByteSequence.byteSequence(bytes));
   }

   public static RememberMeSecret rememberMeSecret(@NonNull String base64UrlString) {
      if (base64UrlString == null) {
         throw new NullPointerException("base64UrlString is marked non-null but is null");
      } else {
         return new RememberMeSecret(ByteSequence.byteSequence(Base64Util.decodeUrlSafe(base64UrlString)));
      }
   }

   public static Optional<RememberMeSecret> parseRememberMeSecret(@Nullable String base64UrlString) {
      try {
         return Optional.ofNullable(base64UrlString).filter(StringUtils::isNotBlank).map(RememberMeSecret::rememberMeSecret);
      } catch (Exception e) {
         LOG.debug("Error while parsing Remember-Me secret: " + e.getMessage());
         return Optional.empty();
      }
   }

   public static RememberMeSecret randomRememberMeSecret() {
      byte[] secret = new byte[150];
      SeededSecureRandom.getInstance().nextBytes(secret);
      return rememberMeSecret(secret);
   }

   @Override
   public String toString() {
      return "RememberMeSecret(***)";
   }

   public String base64Url() {
      return this.secret.base64Url();
   }

   public RememberMeSecretHash hash() {
      return RememberMeSecretHash.rememberMeTokenHash(this.secret.sha512().bytes());
   }
}
