package com.airlock.iam.common.application.configuration.jwt.signature;

import com.airlock.iam.common.domain.model.jwt.signature.JsonWebSignatureToken;
import com.airlock.iam.common.domain.model.jwt.signature.JwsAlgorithmRsa;
import com.airlock.iam.common.domain.service.jwt.signature.JwtSignatureVerifier;
import com.airlock.iam.common.domain.service.jwt.signature.JwtSignatureVerifierException;
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.EnumProperty;
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.PropertyConfigurationException;
import com.airlock.iam.plugin.api.valuereader.EnumPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.util.Objects;

@Plugin(
   description = "<p>Configures the RSA based JWT signature verifier.</p><p>This plugin can be used for JWT signature verification. An RSA based signature is created with a private key and must be validated with the corresponding public key.</p>",
   displayName = "JWT Ticket RSA Verifier Settings"
)
public class JwtTicketRsaVerifierSettings extends JwtTicketVerifierSettings {
   @EnumProperty(
      description = "The algorithm used for signature verifying. Signature verification requires an RSA certificate (public key), which will be obtained from the configured keystore using the configured alias.",
      defaultValue = "RS512",
      optional = true,
      displayName = "RSA Signature Algorithm"
   )
   private JwsAlgorithmRsa rsaSignatureAlgorithm;
   private static final String SIGNATURE_ALGORITHM_NAME = "rsaSignatureAlgorithm";
   private JwtSignatureVerifier ticketVerifier;

   public JwtTicketRsaVerifierSettings(File keystorePath, String keystorePassword, String x509CertificateAlias, JwsAlgorithmRsa rsaSignatureAlgorithm) {
      super(keystorePath, keystorePassword, x509CertificateAlias);
      this.rsaSignatureAlgorithm = rsaSignatureAlgorithm;
   }

   @ConfigurationValidator
   public static void validateConfig(PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, Environment valenv) throws PropertyConfigurationException {
      if (valenv == Environment.CURRENT_VM) {
         JwsAlgorithmRsa rsaAlgorithm = (JwsAlgorithmRsa)EnumPropertyValueReader.effectiveConfigEnum(pc, "rsaSignatureAlgorithm", env, context);
         JwtTicketVerifierSettings.validateConfig(pc, env, context, rsaAlgorithm);
      }
   }

   @AfterConfigActivation
   void afterConfigActivation() {
      this.ticketVerifier = buildVerifier(this.rsaSignatureAlgorithm, this.getKeystorePath(), this.getKeystorePassword(), this.getX509CertificateAlias());
   }

   @Override
   public boolean isSignatureValid(JsonWebSignatureToken signedJwt) throws JwtSignatureVerifierException {
      return Objects.requireNonNull(this.ticketVerifier, "AfterConfigActivation has not been called").isSignatureValid(signedJwt);
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class JwtTicketRsaVerifierSettingsBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private File keystorePath;
      @SuppressFBWarnings(justification = "generated code")
      private String keystorePassword;
      @SuppressFBWarnings(justification = "generated code")
      private String x509CertificateAlias;
      @SuppressFBWarnings(justification = "generated code")
      private JwsAlgorithmRsa rsaSignatureAlgorithm;

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

      @SuppressFBWarnings(justification = "generated code")
      public JwtTicketRsaVerifierSettings.JwtTicketRsaVerifierSettingsBuilder keystorePath(File keystorePath) {
         this.keystorePath = keystorePath;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JwtTicketRsaVerifierSettings.JwtTicketRsaVerifierSettingsBuilder keystorePassword(String keystorePassword) {
         this.keystorePassword = keystorePassword;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JwtTicketRsaVerifierSettings.JwtTicketRsaVerifierSettingsBuilder x509CertificateAlias(String x509CertificateAlias) {
         this.x509CertificateAlias = x509CertificateAlias;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JwtTicketRsaVerifierSettings.JwtTicketRsaVerifierSettingsBuilder rsaSignatureAlgorithm(JwsAlgorithmRsa rsaSignatureAlgorithm) {
         this.rsaSignatureAlgorithm = rsaSignatureAlgorithm;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public JwtTicketRsaVerifierSettings build() {
         return new JwtTicketRsaVerifierSettings(this.keystorePath, this.keystorePassword, this.x509CertificateAlias, this.rsaSignatureAlgorithm);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "JwtTicketRsaVerifierSettings.JwtTicketRsaVerifierSettingsBuilder(keystorePath="
            + this.keystorePath
            + ", keystorePassword="
            + this.keystorePassword
            + ", x509CertificateAlias="
            + this.x509CertificateAlias
            + ", rsaSignatureAlgorithm="
            + this.rsaSignatureAlgorithm
            + ")";
      }
   }
}
