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

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.base.domain.service.uri.UrlUtils;
import com.airlock.iam.common.application.configuration.gateway.extractor.ClientCertificateXfccExtractionFormatConfig;
import com.airlock.iam.common.domain.model.request.ClientTlsCertificate;
import com.airlock.iam.security.certificate.CertificateIO;
import jakarta.inject.Inject;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Optional;
import org.apache.commons.lang3.Strings;

@LogicForConfig(ClientCertificateXfccExtractionFormatConfig.class)
public final class ClientCertificateXfccExtractionFormat implements ClientCertificateExtractionFormat {
   private static final String XFCC_SEPARATOR = ",";
   private static final String XFCC_ELEMENT_SEPARATOR = ";";
   private static final String XFCC_KEY_VALUE_SEPARATOR = "=";
   private static final String XFCC_CERT_KEY = "Cert";

   @Override
   public ClientTlsCertificate extractCertificate(String headerValue) {
      try {
         String[] xfccValues = headerValue.split(",");
         Optional<String> pemCert = Arrays.stream(xfccValues)
            .map(xfccValue -> xfccValue.split(";"))
            .flatMap(Arrays::stream)
            .map(String::trim)
            .filter(xfccElement -> Strings.CI.startsWith(xfccElement, "Cert"))
            .map(xfccElement -> xfccElement.split("="))
            .map(keyValuePair -> (String)keyValuePair[1])
            .map(UrlUtils::urlDecode)
            .findFirst();
         if (pemCert.isEmpty()) {
            return ClientTlsCertificate.invalidClientTlsCertificate("Tried to read mTLS certificate from XFCC header but it failed - missing \"Cert\" key.");
         }

         X509Certificate x509Certificate = CertificateIO.certificateFromPemString(pemCert.get());
         return ClientTlsCertificate.validClientTlsCertificate(x509Certificate);
      } catch (CertificateException | ParseException | IllegalArgumentException e) {
         return ClientTlsCertificate.invalidClientTlsCertificate("Tried to read mTLS certificate from XFCC header but it failed - " + e.getMessage());
      }
   }
}
