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

import com.airlock.iam.core.misc.persistency.SqlDataSource;
import com.airlock.iam.database.infrastructure.DatabaseType;
import com.airlock.iam.database.infrastructure.IamTableMapping;
import com.airlock.iam.database.infrastructure.JooqConfig;
import com.airlock.iam.database.infrastructure.TenantId;
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(
   displayName = "OAuth 2.0 Session Repository",
   description = "OAuth 2.0 / OpenID Connect Session Repository for relational databases. Stores information about the user's OAuth 2.0 sessions."
)
@PluginLicenseRestriction(moduleAffiliation = "OAuthServer")
@Groups(groupSequence = {"Basic Settings", "Advanced Settings"}, openGroups = "Basic Settings")
public class OAuth2SessionRepositoryConfig {
   @PluginProperty(displayName = "SQL Data Source", description = "Defines how connections to the database are obtained.", optional = false)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private SqlDataSource sqlDataSource;
   @StringProperty(description = "The name of the database table containing the tokens.", optional = true, defaultValue = "token")
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private String tokenTableName;
   @StringProperty(description = "The name of the database table containing the token assignments.", optional = true, defaultValue = "token_assignment")
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private String tokenAssignmentTableName;
   @BooleanProperty(
      displayName = "Log Queries",
      description = "<p>If enabled, all SQL queries executed on this repository will be written to the module's\ncorresponding log file. This is only effective if the log level is set to at least INFO.</p>\n<p>Warning: query values (including potentially sensitive data) will be logged as well.</p>",
      optional = true,
      defaultValue = "false"
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private boolean logQueries;

   public JooqConfig jooqConfig() {
      return new JooqConfig(
         this.sqlDataSource,
         this.sqlDataSource.getDbType(),
         this.sqlDataSource.getDbType() == DatabaseType.ORACLE ? "oauth2_session_seq" : null,
         List.of(
            IamTableMapping.iamTableMapping("token", this.tokenTableName), IamTableMapping.iamTableMapping("token_assignment", this.tokenAssignmentTableName)
         ),
         this.logQueries,
         TenantId.tenantId("no_tenant")
      );
   }

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

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2SessionRepositoryConfig.OAuth2SessionRepositoryConfigBuilder tokenTableName(String tokenTableName) {
         this.tokenTableName = tokenTableName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2SessionRepositoryConfig.OAuth2SessionRepositoryConfigBuilder tokenAssignmentTableName(String tokenAssignmentTableName) {
         this.tokenAssignmentTableName = tokenAssignmentTableName;
         return this;
      }

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

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

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "OAuth2SessionRepositoryConfig.OAuth2SessionRepositoryConfigBuilder(sqlDataSource="
            + this.sqlDataSource
            + ", tokenTableName="
            + this.tokenTableName
            + ", tokenAssignmentTableName="
            + this.tokenAssignmentTableName
            + ", logQueries="
            + this.logQueries
            + ")";
      }
   }
}
