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

import com.airlock.iam.oauth2.api.domain.model.clientauthentication.ClientAuthenticationMethod;
import com.airlock.iam.oauth2.application.configuration.token.revocation.AuthorizationInvalidationStrategyConfig;
import com.airlock.iam.oauth2.application.configuration.token.revocation.SingleTokenInvalidationStrategyConfig;
import com.airlock.iam.oauth2.domain.model.clientauthentication.method.KnownClientAuthenticationMethod;
import com.airlock.iam.oauth2.domain.model.revocation.TokenInvalidationStrategyConfig;
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.EnumProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

@Plugin(
   description = "<p><a target=\"_blank\" href=\"https://tools.ietf.org/html/rfc7009\">RFC 7009</a> Token Revocation endpoint allows clients to revoke Access and Refresh Tokens.</p><p>The endpoint is available under <tt>/&lt;loginapp-uri&gt;/rest/oauth2/authorization-servers/<i>&lt;as-identifier&gt;</i>/revoke</tt></p>",
   displayName = "OAuth 2.0 Token Revocation Endpoint"
)
@PluginLicenseRestriction(moduleAffiliation = "OAuthServer")
public class OAuth2TokenRevocationConfig {
   @PluginProperty(
      description = "If the revoked token is an access token, this property defines which tokens to invalidate.",
      displayName = "Access Token Revocation Strategy",
      optional = true,
      defaultValue = SingleTokenInvalidationStrategyConfig.class
   )
   private TokenInvalidationStrategyConfig accessTokenInvalidationStrategy;
   @PluginProperty(
      description = "If the revoked token is a refresh token, this property defines which tokens to invalidate.",
      displayName = "Refresh Token Revocation Strategy",
      optional = true,
      defaultValue = AuthorizationInvalidationStrategyConfig.class
   )
   private TokenInvalidationStrategyConfig refreshTokenInvalidationStrategy;
   @EnumProperty(
      description = "<p>Enforce the client authentication of the token revocation endpoint.</p><ul><li>BASIC_AUTH: Basic Authentication using the client id and secret, see <a href=\"https://tools.ietf.org/html/rfc6749#section-2.3.1\" target=\"_blank\">RFC 6749</a>.</li><li>POST_PARAM: Authentication is done using the POST parameters <tt>client_id</tt> and <tt>client_secret</tt>, see <a href=\"https://tools.ietf.org/html/rfc6749#section-2.3.1\" target=\"_blank\">RFC 6749</a>.<br>    <b>Warning:</b> Including the client credentials in the request-body using the two parameters is <b>not recommended</b> for security reasons.</li><li>NONE: No authentication required (should only used for public clients without any credentials). However, a <tt>client_id</tt> parameter must still be provided.</li></ul>",
      defaultValue = "BASIC_AUTH",
      optional = true
   )
   private OAuth2TokenRevocationConfig.TokenRevocationAuthenticationMethod authenticationMethod;

   public ClientAuthenticationMethod getClientAuthenticationMethod() {
      return this.authenticationMethod.getAuthenticationMethod();
   }

   public TokenInvalidationStrategyConfig getAccessTokenInvalidationStrategy() {
      return this.accessTokenInvalidationStrategy;
   }

   public TokenInvalidationStrategyConfig getRefreshTokenInvalidationStrategy() {
      return this.refreshTokenInvalidationStrategy;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public OAuth2TokenRevocationConfig(
      TokenInvalidationStrategyConfig accessTokenInvalidationStrategy,
      TokenInvalidationStrategyConfig refreshTokenInvalidationStrategy,
      OAuth2TokenRevocationConfig.TokenRevocationAuthenticationMethod authenticationMethod
   ) {
      this.accessTokenInvalidationStrategy = accessTokenInvalidationStrategy;
      this.refreshTokenInvalidationStrategy = refreshTokenInvalidationStrategy;
      this.authenticationMethod = authenticationMethod;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class OAuth2TokenRevocationConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private TokenInvalidationStrategyConfig accessTokenInvalidationStrategy;
      @SuppressFBWarnings(justification = "generated code")
      private TokenInvalidationStrategyConfig refreshTokenInvalidationStrategy;
      @SuppressFBWarnings(justification = "generated code")
      private OAuth2TokenRevocationConfig.TokenRevocationAuthenticationMethod authenticationMethod;

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

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2TokenRevocationConfig.OAuth2TokenRevocationConfigBuilder accessTokenInvalidationStrategy(
         TokenInvalidationStrategyConfig accessTokenInvalidationStrategy
      ) {
         this.accessTokenInvalidationStrategy = accessTokenInvalidationStrategy;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2TokenRevocationConfig.OAuth2TokenRevocationConfigBuilder refreshTokenInvalidationStrategy(
         TokenInvalidationStrategyConfig refreshTokenInvalidationStrategy
      ) {
         this.refreshTokenInvalidationStrategy = refreshTokenInvalidationStrategy;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2TokenRevocationConfig.OAuth2TokenRevocationConfigBuilder authenticationMethod(
         OAuth2TokenRevocationConfig.TokenRevocationAuthenticationMethod authenticationMethod
      ) {
         this.authenticationMethod = authenticationMethod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2TokenRevocationConfig build() {
         return new OAuth2TokenRevocationConfig(this.accessTokenInvalidationStrategy, this.refreshTokenInvalidationStrategy, this.authenticationMethod);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "OAuth2TokenRevocationConfig.OAuth2TokenRevocationConfigBuilder(accessTokenInvalidationStrategy="
            + this.accessTokenInvalidationStrategy
            + ", refreshTokenInvalidationStrategy="
            + this.refreshTokenInvalidationStrategy
            + ", authenticationMethod="
            + this.authenticationMethod
            + ")";
      }
   }

   public enum TokenRevocationAuthenticationMethod {
      BASIC_AUTH(KnownClientAuthenticationMethod.BASIC_AUTH_CLIENT_SECRET),
      POST_PARAM(KnownClientAuthenticationMethod.POST_PARAMETERS_CLIENT_SECRET),
      NONE(KnownClientAuthenticationMethod.NONE);

      private final ClientAuthenticationMethod authenticationMethod;

      public ClientAuthenticationMethod getAuthenticationMethod() {
         return this.authenticationMethod;
      }

      @SuppressFBWarnings(justification = "generated code")
      TokenRevocationAuthenticationMethod(final ClientAuthenticationMethod authenticationMethod) {
         this.authenticationMethod = authenticationMethod;
      }
   }
}
