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

import com.airlock.iam.core.misc.persistency.SqlDataSource;
import com.airlock.iam.database.infrastructure.JooqConfig;
import com.airlock.iam.database.infrastructure.TenantId;
import com.airlock.iam.oauth2.api.application.configuration.clientauthentication.OAuth2ClientAuthenticationConfig;
import com.airlock.iam.plugin.api.annotation.config.Groups;
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.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.List;

@Plugin(
   description = "Configures a client authentication that is based on a <a href=\"https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication\" target=\"_blank\"><tt>private_key_jwt</tt></a>.\n<p>The subject and issuer claim in the JWT must be equal to the identifier of a client\n (client_id). The client must have a public key registered in order to verify the signature of the JWT.</p>\n<p>Note: JWTs are persisted, the 'jti' claim must be unique during the lifetime of a JWT (i.e. until it expires). If a JWT with a previously seen 'jti' claim is sent, authentication fails.\n Automatic removal of persisted JWTs (after expiry) can be configured in an OAuth 2.0 Clean-up Task.</p>\n",
   displayName = "OIDC Private Key JWT Authentication"
)
@PluginLicenseRestriction(moduleAffiliation = "OAuthServer")
@Groups(groupSequence = {"Basic Settings", "Advanced Settings"}, openGroups = "Basic Settings")
public final class OpenIdConnectPrivateKeyJwtAuthenticationConfig implements OAuth2ClientAuthenticationConfig {
   @PluginProperty(displayName = "SQL Data Source", description = "Defines where the JWT ID ('jti' claim of the JWT) is persisted.", optional = false)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private SqlDataSource sqlDataSource;
   @BooleanProperty(
      description = "Enable to log SQL queries (only effective if the log level is at least INFO).\nAttention: query values (including potentially sensitive data) will be logged as well.\n",
      optional = true,
      defaultValue = "false"
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private boolean logQueries;
   @StringProperty(
      displayName = "Tenant ID",
      description = "<p>Identifier added to the database records to distinguish between different tenants.</p>\n<p>If left empty, 'no_tenant' is used as the effective value for tenant ID.</p>",
      optional = true,
      maxLength = 50,
      exampleValues = {"customerA", "customerB"},
      validationRegex = "(?!no_tenant$).*"
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private String tenantId;

   public JooqConfig jooqConfig() {
      return new JooqConfig(this.sqlDataSource, this.sqlDataSource.getDbType(), null, List.of(), this.logQueries, TenantId.tenantId(this.tenantId));
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public OpenIdConnectPrivateKeyJwtAuthenticationConfig(SqlDataSource sqlDataSource, boolean logQueries, String tenantId) {
      this.sqlDataSource = sqlDataSource;
      this.logQueries = logQueries;
      this.tenantId = tenantId;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class OpenIdConnectPrivateKeyJwtAuthenticationConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private SqlDataSource sqlDataSource;
      @SuppressFBWarnings(justification = "generated code")
      private boolean logQueries;
      @SuppressFBWarnings(justification = "generated code")
      private String tenantId;

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

      @SuppressFBWarnings(justification = "generated code")
      public OpenIdConnectPrivateKeyJwtAuthenticationConfig.OpenIdConnectPrivateKeyJwtAuthenticationConfigBuilder sqlDataSource(SqlDataSource sqlDataSource) {
         this.sqlDataSource = sqlDataSource;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OpenIdConnectPrivateKeyJwtAuthenticationConfig.OpenIdConnectPrivateKeyJwtAuthenticationConfigBuilder logQueries(boolean logQueries) {
         this.logQueries = logQueries;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OpenIdConnectPrivateKeyJwtAuthenticationConfig.OpenIdConnectPrivateKeyJwtAuthenticationConfigBuilder tenantId(String tenantId) {
         this.tenantId = tenantId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OpenIdConnectPrivateKeyJwtAuthenticationConfig build() {
         return new OpenIdConnectPrivateKeyJwtAuthenticationConfig(this.sqlDataSource, this.logQueries, this.tenantId);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "OpenIdConnectPrivateKeyJwtAuthenticationConfig.OpenIdConnectPrivateKeyJwtAuthenticationConfigBuilder(sqlDataSource="
            + this.sqlDataSource
            + ", logQueries="
            + this.logQueries
            + ", tenantId="
            + this.tenantId
            + ")";
      }
   }
}
