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

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.BooleanProperty;
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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

@Plugin(
   description = "Specifies the format of the client secret passed in the header of OAuth 2.0 requests.",
   displayName = "OAuth 2.0 Header Client Secret (AS)"
)
@PluginLicenseRestriction(moduleAffiliation = "OAuthServer")
public class OAuth2HeaderClientSecretMethodConfig implements OAuth2ClientSecretMethodConfig {
   private static final String CLIENT_ID_PLACEHOLDER = "$CLIENT_ID$";
   private static final String CLIENT_SECRET_PLACEHOLDER = "$CLIENT_SECRET$";
   private static final String CLIENT_SECRET_CUSTOM_HEADER = "client_secret_custom_header";
   @StringProperty(description = "Name of the header field containing the client secret.", optional = true, defaultValue = "Authorization")
   private String headerField;
   @StringProperty(
      description = "Header field value prefix. The prefix must match exactly. May be empty.<br>A header prefix denotes the first part of a space delimited header value.<br>Eg. \"Authorization: Basic 2q93nf8q23UIZFR2qfh98\" where \"Authorization\" denotes the header field name, \"Basic\" the header prefix and \"2q93nf8q23UIZFR2qfh98\" the client secret value.",
      optional = true,
      suggestedValues = "Basic"
   )
   private String headerPrefix;
   @StringProperty(
      description = "Client secret extraction pattern. If left blank, the client secret is the whole string. Otherwise this field must contain \"$CLIENT_SECRET$\" exactly once and may additionally contain \"$CLIENT_ID$\". When building requests the placeholders get replaced by their respective values, as specified in the OAuth 2.0 identity propagator plugin.",
      suggestedValues = "$CLIENT_ID$:$CLIENT_SECRET$",
      optional = true
   )
   private String clientSecretFormat;
   private static final String CLIENT_SECRET_FORMAT_FIELD = "clientSecretFormat";
   private static final OAuth2HeaderClientSecretConfigValidator CLIENT_SECRET_CONFIG_VALIDATOR = new OAuth2HeaderClientSecretConfigValidator(
      "clientSecretFormat", "$CLIENT_SECRET$"
   );
   @BooleanProperty(
      description = "Flag indicating whether the entire value (behind the optional prefix) is encoded in Base64; must be enabled for Basic-Auth.",
      optional = true,
      defaultValue = "false",
      displayName = "Base64-Encoded Client Secret Value"
   )
   private boolean base64EncodeClientSecretValue;

   @ConfigurationValidator
   public static void checkExactlyOneSecretPlaceholder(
      PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      CLIENT_SECRET_CONFIG_VALIDATOR.checkExactlyOneSecretPlaceholder(config, env, context);
   }

   public String getHeaderField() {
      return this.headerField;
   }

   public String getHeaderPrefix() {
      return this.headerPrefix;
   }

   public String getClientSecretFormat() {
      return this.clientSecretFormat;
   }

   public boolean isBase64EncodeClientSecretValue() {
      return this.base64EncodeClientSecretValue;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public OAuth2HeaderClientSecretMethodConfig(String headerField, String headerPrefix, String clientSecretFormat, boolean base64EncodeClientSecretValue) {
      this.headerField = headerField;
      this.headerPrefix = headerPrefix;
      this.clientSecretFormat = clientSecretFormat;
      this.base64EncodeClientSecretValue = base64EncodeClientSecretValue;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class OAuth2HeaderClientSecretMethodConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String headerField;
      @SuppressFBWarnings(justification = "generated code")
      private String headerPrefix;
      @SuppressFBWarnings(justification = "generated code")
      private String clientSecretFormat;
      @SuppressFBWarnings(justification = "generated code")
      private boolean base64EncodeClientSecretValue;

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

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2HeaderClientSecretMethodConfig.OAuth2HeaderClientSecretMethodConfigBuilder headerField(String headerField) {
         this.headerField = headerField;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2HeaderClientSecretMethodConfig.OAuth2HeaderClientSecretMethodConfigBuilder headerPrefix(String headerPrefix) {
         this.headerPrefix = headerPrefix;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2HeaderClientSecretMethodConfig.OAuth2HeaderClientSecretMethodConfigBuilder clientSecretFormat(String clientSecretFormat) {
         this.clientSecretFormat = clientSecretFormat;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2HeaderClientSecretMethodConfig.OAuth2HeaderClientSecretMethodConfigBuilder base64EncodeClientSecretValue(
         boolean base64EncodeClientSecretValue
      ) {
         this.base64EncodeClientSecretValue = base64EncodeClientSecretValue;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2HeaderClientSecretMethodConfig build() {
         return new OAuth2HeaderClientSecretMethodConfig(this.headerField, this.headerPrefix, this.clientSecretFormat, this.base64EncodeClientSecretValue);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "OAuth2HeaderClientSecretMethodConfig.OAuth2HeaderClientSecretMethodConfigBuilder(headerField="
            + this.headerField
            + ", headerPrefix="
            + this.headerPrefix
            + ", clientSecretFormat="
            + this.clientSecretFormat
            + ", base64EncodeClientSecretValue="
            + this.base64EncodeClientSecretValue
            + ")";
      }
   }
}
