package com.airlock.iam.techclient.application.configuration;

import com.airlock.iam.common.application.configuration.security.StorageEncryptionConfig;
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.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 com.airlock.iam.security.util.crypto.StringCipher;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.List;

@Plugin(
   description = "Persists and loads technical clients and associated data from the configured data source.",
   displayName = "Technical Client Database Repository"
)
@PluginLicenseRestriction(moduleAffiliation = "TechClients")
@Groups(groupSequence = {"Basic Settings", "Advanced Settings", "Legacy Settings"}, openGroups = "Basic Settings")
public final class TechClientRepositoryConfig {
   @PluginProperty(displayName = "SQL Data Source", description = "Defines how connections to the database are obtained.", optional = false)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private SqlDataSource sqlDataSource;
   @PluginProperty(
      displayName = "Storage Encryption",
      description = "Defines how sensitive values are encrypted when stored on the database. This ensures that an adversary obtaining data from the database cannot read or modify sensitive values without knowing the secret for decryption.",
      optional = false
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private StorageEncryptionConfig storageEncryptionConfig;
   @BooleanProperty(
      displayName = "Log Queries",
      description = "Enable to log SQL queries (only effective if the log level is at least INFO). Attention: query values (including potentially sensitive data) will be logged as well.",
      optional = true,
      defaultValue = "false"
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private boolean logQueries;
   @StringProperty(
      displayName = "Tenant ID",
      description = "The value which is used in queries related to technical clients to distinguish between different tenants.<p>If no value is configured, then 'no_tenant' is used as value on the database.</p>",
      optional = true,
      maxLength = 50,
      exampleValues = {"customerA", "customerB"},
      validationRegex = "(?!no_tenant$).*"
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private String tenantId;
   static final String TENANT_ID_FIELD = "tenantId";
   @PluginProperty(
      description = "<p>Cipher to encrypt and decrypt sensitive values in the database.</p><p>This setting is deprecated and has been replaced by <i>Storage Encryption</i>. If set, this property was configured by an automatic configuration migration and should not be changed manually. The property takes precedence over <i>Storage Encryption</i>, which means that OAuth 2.0 client secrets will be encrypted / decrypted using this cipher for backward compatibility. Other secrets on the DB are not affected by this property. <p>To migrate from <i>Cipher</i> to <i>Storage Encryption</i>, encrypted data on the DB must be changed manually. Please contact Airlock Support for further guidelines.</p>",
      optional = true
   )
   @GroupProperty(groupIdentifier = "Legacy Settings")
   private StringCipher cipher;

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

   public SqlDataSource getSqlDataSource() {
      return this.sqlDataSource;
   }

   public StorageEncryptionConfig getStorageEncryptionConfig() {
      return this.storageEncryptionConfig;
   }

   public boolean isLogQueries() {
      return this.logQueries;
   }

   public String getTenantId() {
      return this.tenantId;
   }

   public StringCipher getCipher() {
      return this.cipher;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public TechClientRepositoryConfig(
      SqlDataSource sqlDataSource, StorageEncryptionConfig storageEncryptionConfig, boolean logQueries, String tenantId, StringCipher cipher
   ) {
      this.sqlDataSource = sqlDataSource;
      this.storageEncryptionConfig = storageEncryptionConfig;
      this.logQueries = logQueries;
      this.tenantId = tenantId;
      this.cipher = cipher;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class TechClientRepositoryConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private SqlDataSource sqlDataSource;
      @SuppressFBWarnings(justification = "generated code")
      private StorageEncryptionConfig storageEncryptionConfig;
      @SuppressFBWarnings(justification = "generated code")
      private boolean logQueries;
      @SuppressFBWarnings(justification = "generated code")
      private String tenantId;
      @SuppressFBWarnings(justification = "generated code")
      private StringCipher cipher;

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

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

      @SuppressFBWarnings(justification = "generated code")
      public TechClientRepositoryConfig.TechClientRepositoryConfigBuilder storageEncryptionConfig(StorageEncryptionConfig storageEncryptionConfig) {
         this.storageEncryptionConfig = storageEncryptionConfig;
         return this;
      }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public TechClientRepositoryConfig.TechClientRepositoryConfigBuilder cipher(StringCipher cipher) {
         this.cipher = cipher;
         return this;
      }

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

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