package com.airlock.iam.admin.application.configuration.generic;

import com.airlock.iam.admin.api.application.configuration.token.generic.GenericTokenRepositoryConfig;
import com.airlock.iam.admin.api.domain.model.administrator.CurrentAdministrator;
import com.airlock.iam.admin.api.domain.model.token.generic.GenericTokenAttributeMapping;
import com.airlock.iam.admin.api.domain.model.token.generic.GenericTokenRepository;
import com.airlock.iam.admin.application.service.token.generic.CredentialBasedGenericTokenConverter;
import com.airlock.iam.admin.application.service.token.generic.CredentialBasedGenericTokenRepository;
import com.airlock.iam.core.misc.persistency.CredentialPersister;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.property.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Optional;

@Plugin(
   description = "<p>Repository that loads credentials as tokens from persistence.</p>If configured, the credential model supports a 'current' and 'next' credential. The db columns can be specified in the configured 'Credential Persister'.",
   displayName = "Credential-based Generic Token Repository"
)
public class CredentialBasedGenericTokenRepositoryConfig implements GenericTokenRepositoryConfig {
   @PluginProperty(description = "Credential Persister to load credentials from persistence.", optional = false)
   private CredentialPersister credentialPersister;
   @BooleanProperty(description = "Controls whether a 'next' credential is supported.", defaultValue = "false", optional = true)
   private boolean supportCurrentAndNextCredential;
   @BooleanProperty(
      description = "Controls whether a 'next' credential is automatically used as new 'current' on deletion of an old 'current'. Has no effect if 'next' credential is not supported.",
      defaultValue = "true",
      optional = true
   )
   private boolean useNextAsCurrentOnDeletion;
   @PluginProperty(
      description = "Defines the set of supported attributes and optional name mappings.",
      optional = true,
      displayName = "Token Attribute Mapping",
      defaultValue = CredentialBasedAttributeMapping.class
   )
   private GenericTokenAttributeMappingConfig attributeMapping;

   @Override
   public GenericTokenRepository getRepository(String tokenType, CurrentAdministrator administrator) {
      return CredentialBasedGenericTokenRepository.builder()
         .supportNextCredential(this.supportCurrentAndNextCredential)
         .credentialPersister(this.credentialPersister)
         .useNextAsCurrentOnDeletion(this.useNextAsCurrentOnDeletion)
         .administrator(administrator)
         .mapper(new CredentialBasedGenericTokenConverter())
         .build();
   }

   @Override
   public int getMaxTokensPerUser() {
      return this.supportCurrentAndNextCredential ? 2 : 1;
   }

   @Override
   public Optional<String> getEnabledProperty() {
      return this.attributeMapping.getMappingForEnabled();
   }

   @Override
   public GenericTokenAttributeMapping getAttributeMapping() {
      return this.attributeMapping.getMapping();
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public CredentialBasedGenericTokenRepositoryConfig(
      CredentialPersister credentialPersister,
      boolean supportCurrentAndNextCredential,
      boolean useNextAsCurrentOnDeletion,
      GenericTokenAttributeMappingConfig attributeMapping
   ) {
      this.credentialPersister = credentialPersister;
      this.supportCurrentAndNextCredential = supportCurrentAndNextCredential;
      this.useNextAsCurrentOnDeletion = useNextAsCurrentOnDeletion;
      this.attributeMapping = attributeMapping;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class CredentialBasedGenericTokenRepositoryConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private CredentialPersister credentialPersister;
      @SuppressFBWarnings(justification = "generated code")
      private boolean supportCurrentAndNextCredential;
      @SuppressFBWarnings(justification = "generated code")
      private boolean useNextAsCurrentOnDeletion;
      @SuppressFBWarnings(justification = "generated code")
      private GenericTokenAttributeMappingConfig attributeMapping;

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

      @SuppressFBWarnings(justification = "generated code")
      public CredentialBasedGenericTokenRepositoryConfig.CredentialBasedGenericTokenRepositoryConfigBuilder credentialPersister(
         CredentialPersister credentialPersister
      ) {
         this.credentialPersister = credentialPersister;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CredentialBasedGenericTokenRepositoryConfig.CredentialBasedGenericTokenRepositoryConfigBuilder supportCurrentAndNextCredential(
         boolean supportCurrentAndNextCredential
      ) {
         this.supportCurrentAndNextCredential = supportCurrentAndNextCredential;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CredentialBasedGenericTokenRepositoryConfig.CredentialBasedGenericTokenRepositoryConfigBuilder useNextAsCurrentOnDeletion(
         boolean useNextAsCurrentOnDeletion
      ) {
         this.useNextAsCurrentOnDeletion = useNextAsCurrentOnDeletion;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CredentialBasedGenericTokenRepositoryConfig.CredentialBasedGenericTokenRepositoryConfigBuilder attributeMapping(
         GenericTokenAttributeMappingConfig attributeMapping
      ) {
         this.attributeMapping = attributeMapping;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public CredentialBasedGenericTokenRepositoryConfig build() {
         return new CredentialBasedGenericTokenRepositoryConfig(
            this.credentialPersister, this.supportCurrentAndNextCredential, this.useNextAsCurrentOnDeletion, this.attributeMapping
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "CredentialBasedGenericTokenRepositoryConfig.CredentialBasedGenericTokenRepositoryConfigBuilder(credentialPersister="
            + this.credentialPersister
            + ", supportCurrentAndNextCredential="
            + this.supportCurrentAndNextCredential
            + ", useNextAsCurrentOnDeletion="
            + this.useNextAsCurrentOnDeletion
            + ", attributeMapping="
            + this.attributeMapping
            + ")";
      }
   }
}
