package com.airlock.iam.common.domain.service.credential;

import com.airlock.iam.base.misc.util.Base64Util;
import com.airlock.iam.common.api.domain.model.password.Password;
import com.airlock.iam.common.api.domain.model.user.ProvidedUsername;
import com.airlock.iam.common.domain.model.password.PasswordImpl;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import java.nio.charset.Charset;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;

public final class HttpBasicAuthExtractor {
   private static final ELogger LOG = ELoggerFactory.getLogger(HttpBasicAuthExtractor.class);
   private static final String BASIC_AUTH_SCHEME = "Basic";

   public static Optional<HttpBasicAuthExtractor.BasicAuthHeader> extractBasicAuthHeader(Optional<String> authorizationHeaderValue, Charset charset) {
      return authorizationHeaderValue.<String>map(StringUtils::trimToNull)
         .filter(header -> header.startsWith("Basic "))
         .map(header -> Strings.CS.removeStart(header, "Basic"))
         .<String>map(StringUtils::trimToNull)
         .flatMap(value -> decodeBasicAuthHeader(value, charset));
   }

   public static Optional<HttpBasicAuthExtractor.BasicAuthHeader> decodeBasicAuthHeader(String encoded, Charset charset) {
      Optional<String> decoded = safeDecodeBase64(encoded, charset);
      if (decoded.isEmpty()) {
         return Optional.empty();
      }

      int index = decoded.get().indexOf(58);
      if (index > 0) {
         String username = decoded.get().substring(0, index);
         String password = decoded.get().substring(index + 1);
         if (password.isEmpty()) {
            LOG.debug("Empty basic auth password.");
            return Optional.empty();
         } else {
            return Optional.of(new HttpBasicAuthExtractor.BasicAuthHeader(ProvidedUsername.providedUsernameOf(username), PasswordImpl.passwordOf(password)));
         }
      } else {
         return Optional.empty();
      }
   }

   private static Optional<String> safeDecodeBase64(String encoded, Charset charset) {
      try {
         return Optional.of(new String(Base64Util.decode(encoded), charset));
      } catch (IllegalArgumentException e) {
         LOG.info("Unable to decode Basic Auth header: " + e.getMessage());
         return Optional.empty();
      }
   }

   private HttpBasicAuthExtractor() {
   }

   public record BasicAuthHeader(ProvidedUsername username, Password password) {
   }
}
