package com.airlock.iam.common.domain.model.certificate;

import com.airlock.iam.common.api.domain.model.user.ProvidedUsername;
import com.airlock.iam.core.misc.authen.AuthenticatorException;
import com.airlock.iam.core.misc.impl.authen.certificate.CertificateContentExtractor;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.security.cert.X509Certificate;
import java.util.Optional;

public final class UserAttributeExtractorImpl implements UserAttributeExtractor {
   private static final ELogger LOG = ELoggerFactory.getLogger(UserAttributeExtractorImpl.class);
   private static final String ATTR_DN = "dn";
   private static final String ATTR_ALT_SUBJECT_NAME = "subjectAlternativeName";
   private static final String ATTR_CERTIFICATE = "certificate";
   private final Provider<ClientCertificateAuthenticationSettings> settings;

   @Inject
   public UserAttributeExtractorImpl(Provider<ClientCertificateAuthenticationSettings> settings) {
      this.settings = settings;
   }

   @Override
   public Optional<ProvidedUsername> extractUserAttribute(X509Certificate certificate) {
      String providedUsernameAttribute = ((ClientCertificateAuthenticationSettings)this.settings.get()).providedUsernameAttribute();

      try {
         if (providedUsernameAttribute.equalsIgnoreCase("dn")) {
            return Optional.of(extractSubjectDn(certificate));
         } else if (providedUsernameAttribute.equalsIgnoreCase("certificate")) {
            return Optional.of(extractEntireContent(certificate));
         } else {
            return providedUsernameAttribute.equalsIgnoreCase("subjectAlternativeName")
               ? Optional.of(extractFirstAlternativeSubjectName(certificate))
               : Optional.of(extractAttributeValueFromDn(certificate, providedUsernameAttribute));
         }
      } catch (AuthenticatorException e) {
         LOG.info("Provided username extraction from certificate failed: " + e.getMessage());
         return Optional.empty();
      }
   }

   private static ProvidedUsername extractSubjectDn(X509Certificate certificate) throws AuthenticatorException {
      return ProvidedUsername.providedUsernameOf(CertificateContentExtractor.extractSubjectDn(certificate));
   }

   private static ProvidedUsername extractEntireContent(X509Certificate certificate) throws AuthenticatorException {
      return ProvidedUsername.providedUsernameOf(CertificateContentExtractor.extractEntireContent(certificate));
   }

   private static ProvidedUsername extractFirstAlternativeSubjectName(X509Certificate certificate) throws AuthenticatorException {
      return ProvidedUsername.providedUsernameOf(CertificateContentExtractor.extractFirstAlternativeSubjectName(certificate, false));
   }

   private static ProvidedUsername extractAttributeValueFromDn(X509Certificate certificate, String dnAttribute) throws AuthenticatorException {
      return ProvidedUsername.providedUsernameOf(CertificateContentExtractor.extractAttributeValueFromDn(certificate, dnAttribute, false));
   }
}
