package com.airlock.iam.login.app.misc.oneshot.impl;

import com.airlock.iam.core.domain.model.http.HttpRequest;
import com.airlock.iam.core.domain.model.http.signature.key.HttpSignatureCertificateLoader;
import com.airlock.iam.core.domain.model.http.signature.key.X509CertificateFactory;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.lifecycle.AfterConfigActivation;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.Environment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.exception.PropertyTypeMismatchException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.Optional;

@Plugin(description = "Returns the configured certificate.", displayName = "HTTP Signature Static X.509 Certificate Loader")
public final class HttpSignatureStaticX509CertificateLoaderConfig implements HttpSignatureCertificateLoaderConfig {
   @StringProperty(description = "The certificate in PEM format.", displayName = "Certificate (PEM)", isMultiLineText = true, optional = false)
   private String pemCertificate;
   static final String PEM_CERTIFICATE_FIELD = "pemCertificate";
   private X509Certificate certificate;

   public HttpSignatureStaticX509CertificateLoaderConfig(String pemCertificate) {
      this.pemCertificate = pemCertificate;
   }

   @Override
   public HttpSignatureCertificateLoader create(HttpRequest request) {
      return keyId -> Optional.of(this.certificate);
   }

   @ConfigurationValidator
   static void validateCertificate(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment) throws PropertyTypeMismatchException, PropertyConstraintViolationException {
      String pem = StringPropertyValueReader.effectiveStringConfigValue(config, "pemCertificate", env, context);
      if (generateCertificate(pem).isEmpty()) {
         throw new PropertyConstraintViolationException("pemCertificate", config, env, context, "Invalid PEM certificate");
      }
   }

   @AfterConfigActivation
   void initializeCertificate() {
      this.certificate = generateCertificate(this.pemCertificate).orElseThrow();
   }

   private static Optional<X509Certificate> generateCertificate(String pemCertificate) {
      return X509CertificateFactory.certificateFactory().generate(pemCertificate.getBytes(StandardCharsets.UTF_8));
   }

   @SuppressFBWarnings(justification = "generated code")
   public static HttpSignatureStaticX509CertificateLoaderConfig.HttpSignatureStaticX509CertificateLoaderConfigBuilder builder() {
      return new HttpSignatureStaticX509CertificateLoaderConfig.HttpSignatureStaticX509CertificateLoaderConfigBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public HttpSignatureStaticX509CertificateLoaderConfig() {
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class HttpSignatureStaticX509CertificateLoaderConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String pemCertificate;

      @SuppressFBWarnings(justification = "generated code")
      HttpSignatureStaticX509CertificateLoaderConfigBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public HttpSignatureStaticX509CertificateLoaderConfig.HttpSignatureStaticX509CertificateLoaderConfigBuilder pemCertificate(String pemCertificate) {
         this.pemCertificate = pemCertificate;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public HttpSignatureStaticX509CertificateLoaderConfig build() {
         return new HttpSignatureStaticX509CertificateLoaderConfig(this.pemCertificate);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "HttpSignatureStaticX509CertificateLoaderConfig.HttpSignatureStaticX509CertificateLoaderConfigBuilder(pemCertificate="
            + this.pemCertificate
            + ")";
      }
   }
}
