package com.airlock.iam.oauth2.application.configuration.clientauthentication;

import com.airlock.iam.common.domain.model.jwt.signature.KeyId;
import com.airlock.iam.oauth2.domain.model.client.OAuth2ClientPublicKey;
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.license.PluginLicenseRestriction;
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.ConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

@Plugin(
   description = "RSA or EC public key used by an OAuth 2.0 client for authentication to the authorization server,\ne.g. when accessing the token endpoint (if configured to use\n<a href=\"https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication\" target=\"_blank\"><tt>private_key_jwt</tt></a>)\n",
   displayName = "OAuth 2.0 Client Public Key"
)
@PluginLicenseRestriction(moduleAffiliation = "OAuthServer")
public final class OAuth2ClientPublicKeyConfig {
   @StringProperty(
      description = "An RSA or EC public key encoded using Base64. It can optionally be wrapped in\n\"<tt>-----BEGIN PUBLIC KEY-----</tt>\" and \"<tt>-----END PUBLIC KEY-----</tt>\".\n",
      optional = false,
      isMultiLineText = true
   )
   private String publicKey;
   static final String PUBLIC_KEY_FIELD = "publicKey";
   @StringProperty(
      displayName = "Key ID",
      description = "Used to differentiate between multiple public keys, optional if only one key is configured.\n<p>Must match the value of the \"kid\" sent in the header of the private_key_jwt JWT.</p>\n<p>Note that the \"Key ID\" property is only optional if a singular public key is configured. If more than one public key is configured, each must have a (unique) Key ID.</p>\n",
      optional = true
   )
   private String keyId;
   public static final String KEY_ID_PROPERTY_NAME = "keyId";

   public OAuth2ClientPublicKey getPublicKey() {
      return OAuth2ClientPublicKey.builder(this.publicKey).keyId(new KeyId(this.keyId)).build();
   }

   @ConfigurationValidator
   static void validatePublicKey(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment) throws ConfigurationException {
      String rawPublicKey = StringPropertyValueReader.effectiveStringConfigValue(config, "publicKey", env, context);

      try {
         OAuth2ClientPublicKey.builder(rawPublicKey);
      } catch (IllegalArgumentException e) {
         throw new PropertyConstraintViolationException("publicKey", config, env, context, "The configured base 64 public key is invalid.");
      }
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public OAuth2ClientPublicKeyConfig(String publicKey, String keyId) {
      this.publicKey = publicKey;
      this.keyId = keyId;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class OAuth2ClientPublicKeyConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String publicKey;
      @SuppressFBWarnings(justification = "generated code")
      private String keyId;

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

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2ClientPublicKeyConfig.OAuth2ClientPublicKeyConfigBuilder publicKey(String publicKey) {
         this.publicKey = publicKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2ClientPublicKeyConfig.OAuth2ClientPublicKeyConfigBuilder keyId(String keyId) {
         this.keyId = keyId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2ClientPublicKeyConfig build() {
         return new OAuth2ClientPublicKeyConfig(this.publicKey, this.keyId);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "OAuth2ClientPublicKeyConfig.OAuth2ClientPublicKeyConfigBuilder(publicKey=" + this.publicKey + ", keyId=" + this.keyId + ")";
      }
   }
}
