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.JwsAlgorithmEc;
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 EC based JWT signature verifier.</p><p>This plugin can be used for JWT signature verification. An EC based signature is created with a private key and must be validated with the corresponding public key.</p>",
   displayName = "JWT Ticket EC Verifier Settings"
)
public class JwtTicketEcVerifierSettings extends JwtTicketVerifierSettings {
   @EnumProperty(
      description = "The algorithm used for signature verifying. Signature verification requires an EC certificate (public key), which will be obtained from the configured keystore using the configured alias.<br/><br/>According to the selected algorithm, the private key must be derived from a specific curve:<br/><ul><li>ES512: NIST Curve P521</li><li>ES384: NIST Curve P384</li><li>ES256: NIST Curve P256</li></ul>",
      defaultValue = "ES512",
      optional = true,
      displayName = "EC Signature Algorithm"
   )
   private JwsAlgorithmEc ecSignatureAlgorithm;
   private static final String SIGNATURE_ALGORITHM_NAME = "ecSignatureAlgorithm";
   private JwtSignatureVerifier ticketVerifier;

   public JwtTicketEcVerifierSettings(File keystorePath, String keystorePassword, String x509CertificateAlias, JwsAlgorithmEc ecSignatureAlgorithm) {
      super(keystorePath, keystorePassword, x509CertificateAlias);
      this.ecSignatureAlgorithm = ecSignatureAlgorithm;
   }

   @ConfigurationValidator(localOnly = true)
   public static void validateConfig(PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, Environment valenv) throws PropertyConfigurationException {
      if (valenv == Environment.CURRENT_VM) {
         JwsAlgorithmEc ecAlgorithm = (JwsAlgorithmEc)EnumPropertyValueReader.effectiveConfigEnum(pc, "ecSignatureAlgorithm", env, context);
         validateConfig(pc, env, context, ecAlgorithm);
      }
   }

   @AfterConfigActivation
   void afterConfigActivation() {
      this.ticketVerifier = buildVerifier(this.ecSignatureAlgorithm, 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 JwtTicketEcVerifierSettings.JwtTicketEcVerifierSettingsBuilder builder() {
      return new JwtTicketEcVerifierSettings.JwtTicketEcVerifierSettingsBuilder();
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class JwtTicketEcVerifierSettingsBuilder {
      @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 JwsAlgorithmEc ecSignatureAlgorithm;

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public JwtTicketEcVerifierSettings.JwtTicketEcVerifierSettingsBuilder ecSignatureAlgorithm(JwsAlgorithmEc ecSignatureAlgorithm) {
         this.ecSignatureAlgorithm = ecSignatureAlgorithm;
         return this;
      }

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

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