package com.airlock.iam.oauth2.infrastructure.credential;

import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.oauth2.domain.model.parser.RawOAuth2TokenParser;
import com.airlock.iam.oauth2.domain.model.settings.AccessTokenHeaderSettings;
import com.airlock.iam.oauth2.domain.model.token.RawOAuth2Token;
import jakarta.inject.Inject;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;

public final class OAuth2AccessTokenExtractionServiceImpl implements OAuth2AccessTokenExtractionService {
   private static final ELogger LOG = ELoggerFactory.getLogger(OAuth2AccessTokenExtractionServiceImpl.class);
   private final Optional<AccessTokenHeaderSettings> settings;

   @Inject
   public OAuth2AccessTokenExtractionServiceImpl(Optional<AccessTokenHeaderSettings> settings) {
      this.settings = settings;
   }

   @Override
   public Optional<RawOAuth2Token> extractAccessToken(HttpServletRequest request) {
      if (this.settings.isEmpty()) {
         LOG.debug("No AS configuration present. Cannot extract Access Token.");
         return Optional.empty();
      } else {
         return this.extractRawToken(this.settings.get(), request).flatMap(t -> this.tokenParser(this.settings.get()).parseRawOAuth2Token(t));
      }
   }

   private RawOAuth2TokenParser tokenParser(AccessTokenHeaderSettings headerSettings) {
      return new RawOAuth2TokenParser(headerSettings.getTokenRepresentation());
   }

   private Optional<String> extractRawToken(AccessTokenHeaderSettings accessTokenHeaderSettings, HttpServletRequest request) {
      String rawHeader = StringUtils.trimToNull(request.getHeader(accessTokenHeaderSettings.getHeaderName()));
      if (rawHeader == null) {
         LOG.debug("Header " + LogUtil.quote(accessTokenHeaderSettings.getHeaderName()) + " is not present or empty. Cannot extract Access Token.");
         return Optional.empty();
      } else if (accessTokenHeaderSettings.getHeaderPrefixCaseInsensitive().isEmpty()) {
         return Optional.of(rawHeader);
      } else {
         String expectedPrefix = accessTokenHeaderSettings.getHeaderPrefixCaseInsensitive().get() + " ";
         if (!Strings.CI.startsWith(rawHeader, expectedPrefix)) {
            LOG.debug("Header does not start with " + LogUtil.quote(expectedPrefix) + ". Cannot extract Access Token.");
            return Optional.empty();
         } else {
            return Optional.of(Strings.CI.removeStart(rawHeader, expectedPrefix));
         }
      }
   }
}
