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

import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.core.domain.model.http.HttpRequestHeader;
import com.airlock.iam.core.domain.model.http.HttpRequestParameter;
import com.airlock.iam.core.misc.plugin.config.validation.CharsetValidator;
import com.airlock.iam.oauth2.api.domain.model.clientauthentication.ClientAuthenticationMethod;
import com.airlock.iam.oauth2.domain.model.client.OAuth2ClientSideCredentials;
import com.airlock.iam.oauth2.domain.model.client.communication.OAuth2TokenRequestClientSecretProcessor;
import com.airlock.iam.oauth2.domain.model.clientauthentication.method.KnownClientAuthenticationMethod;
import com.airlock.iam.oauth2.domain.service.OAuth2BasicAuthHeaderUtils;
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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.List;

@Plugin(
   description = "Basic auth scheme for OAuth 2.0 requests.<p><b>Note</b>: The basic auth scheme in OAuth 2.0 requests must comply to the specification in <a href=\"https://tools.ietf.org/html/rfc6749#section-2.3.1\" target=\"_blank\">RFC 6749</a></p>",
   displayName = "OAuth 2.0 Basic Auth Client Secret"
)
@PluginLicenseRestriction(moduleAffiliation = "OAuthClient")
public class OAuth2BasicAuthClientSecretConfig implements OAuth2TokenRequestClientSecretProcessor {
   public static final String OAUTH_2_BASIC_AUTH_CLIENT_SECRET = "OAuth 2.0 Basic Auth Client Secret";
   @StringProperty(
      description = "Defines the charset of the Basic Auth HTTP header. If you have trouble accepting special characters, try \"ISO-8859-1\" instead.",
      exampleValues = {"UTF-8", "ISO-8859-1"},
      defaultValue = "UTF-8",
      optional = true
   )
   private String charset;
   static final String CHARSET_FIELD = "charset";

   @ConfigurationValidator
   public static void checkCharset(PluginConfiguration configuration, ConfigurationEnvironment env, ConfigurationContext context, Environment environment) throws ConfigurationException {
      CharsetValidator.validateCharsetProperty("charset", configuration, env, context);
   }

   @Override
   public void putClientSecretInRequestData(
      URI baseUri, List<HttpRequestParameter> params, List<HttpRequestHeader> headers, OAuth2ClientSideCredentials clientCredentials
   ) {
      headers.add(
         HttpRequestHeader.httpRequestHeader(
            "Authorization",
            OAuth2BasicAuthHeaderUtils.oauth2BasicAuthHeader(
               clientCredentials.clientId().id(),
               clientCredentials.clientSecret().orElseThrow(() -> new ViolationException("Missing client secret in config")),
               this.getCharset()
            )
         )
      );
   }

   @Override
   public ClientAuthenticationMethod clientAuthenticationMethod() {
      return KnownClientAuthenticationMethod.BASIC_AUTH_CLIENT_SECRET;
   }

   private Charset getCharset() {
      return Charset.forName(this.charset);
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public OAuth2BasicAuthClientSecretConfig(String charset) {
      this.charset = charset;
   }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2BasicAuthClientSecretConfig.OAuth2BasicAuthClientSecretConfigBuilder charset(String charset) {
         this.charset = charset;
         return this;
      }

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

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "OAuth2BasicAuthClientSecretConfig.OAuth2BasicAuthClientSecretConfigBuilder(charset=" + this.charset + ")";
      }
   }
}
