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

import com.airlock.iam.core.misc.renderer.TokenListRenderer;
import com.airlock.iam.core.misc.tanserver.core.TokenType.Alphabet;
import com.airlock.iam.core.misc.util.password.hash.PasswordHash;
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.EnumProperty;
import com.airlock.iam.plugin.api.annotation.property.FileProperty;
import com.airlock.iam.plugin.api.annotation.property.IntegerProperty;
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 jakarta.annotation.Nullable;
import java.io.File;
import java.util.Optional;

@Plugin(description = "Configuration settings for the generation of matrix cards.")
@PluginLicenseRestriction(moduleAffiliation = "Matrixcard")
public final class MatrixCardGeneratorConfig {
   @EnumProperty(description = "Defines the alphabet (or set of characters) of which a token is composed.<br/>", optional = false)
   private Alphabet tokenAlphabet;
   @IntegerProperty(description = "Specifies the length of each token on the token list.", optional = false, minValue = 1, exampleValues = {3, 4, 5, 6})
   private int tokenLength;
   @IntegerProperty(
      description = "Specifies the total number of tokens per token list.",
      optional = false,
      minValue = 1,
      maxValue = 10000,
      exampleValues = {70, 84, 130}
   )
   private int tokensPerList;
   @PluginProperty(
      description = "Specifies the hash function plugin used by this plugin in order to produce hash value of the tokens. Using an insecure hash function (such as the <code>IdentityPasswordHash</code> plugin) results potential security vulnerability in that the token lists may easily be reconstructed from the stored hash values.",
      optional = false
   )
   private PasswordHash hashFunction;
   @PluginProperty(description = "Specifies the token list renderer plugin used.", optional = false)
   private TokenListRenderer tokenListRenderer;
   @BooleanProperty(
      description = "Deletes old rendered token lists of a user from the file system when a new one is rendered. Setting this to TRUE results in at most one rendered token list per user.<br/>If this property is set to TRUE, the plugin must have permission to delete files from the directory.",
      optional = true,
      defaultValue = "true"
   )
   private boolean deleteOldTokenLists;
   @FileProperty(
      description = "A writable directory used to store partial reports.<br/>If this property is defined, the token lists are not directly generated into the output directory (see other property) but they are generated into this working directory and are moved to the output directory once they are done.<br/>This helps to solve problems with processes automatically reading the rendered token lists and reading partial token lists during the generation process. Make sure that the working directory and the output directory reside in the same file system (if not the moving of the generated file will not be atomic).<br/>The directory is either absolute or relative to the JVMs current directory.",
      optional = true,
      isDirectory = true,
      assureExistence = true,
      assureWritable = true,
      exampleValues = "instances/test/pdfs/inwork"
   )
   private File workingDirectory;
   @FileProperty(
      description = "Directory in the file system to put the rendered token lists in. The directory is either absolute or relative to the JVMs current directory.<p>This property is not required if the renderer plugin (see separate property) does not write on the output stream (e.g. sends it somewhere else). It is required otherwise.</p><p><b>Note:</b> If this property is not defined and the used renderer plugin writes on the output stream, then the result (e.g. a PDF file) is lost.</p>",
      optional = true,
      isDirectory = true,
      assureExistence = true,
      assureWritable = true,
      exampleValues = "instances/test/pdfs"
   )
   private File outputDirectory;
   @StringProperty(
      description = "Filename prefix for rendered report files. It is important to set this to a unique value for the kind of reports generated by this task. When this task deletes old reports, it looks at this prefix (and the user id) in order to find out what files to delete. Thus, if this prefix is the same as for other reports and the reside in the same directory, other reports may be deleted.<p>Do not use the prefix \"pwd-\" if password- reports are stored in the same directory. This prefix is the default for password letters (and not configurable in older plugin versions).</p><p>This property is optional to be backwards compatible. It is strongly recommended to define a prefix.</p>",
      optional = true,
      suggestedValues = {"tan-", "matrix-", "gridcard-"}
   )
   private String fileNamePrefix;
   @StringProperty(description = "Filename suffix for rendered token list files.", optional = true, suggestedValues = {".pdf", ".docx", ".txt"})
   private String fileNameSuffix;

   public Optional<File> getOutputDirectory() {
      return Optional.ofNullable(this.outputDirectory);
   }

   public Optional<File> getWorkingDirectory() {
      return Optional.ofNullable(this.workingDirectory);
   }

   public Alphabet getTokenAlphabet() {
      return this.tokenAlphabet;
   }

   public int getTokenLength() {
      return this.tokenLength;
   }

   public int getTokensPerList() {
      return this.tokensPerList;
   }

   public PasswordHash getHashFunction() {
      return this.hashFunction;
   }

   public TokenListRenderer getTokenListRenderer() {
      return this.tokenListRenderer;
   }

   public boolean isDeleteOldTokenLists() {
      return this.deleteOldTokenLists;
   }

   @Nullable
   public String getFileNamePrefix() {
      return this.fileNamePrefix;
   }

   @Nullable
   public String getFileNameSuffix() {
      return this.fileNameSuffix;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public MatrixCardGeneratorConfig(
      Alphabet tokenAlphabet,
      int tokenLength,
      int tokensPerList,
      PasswordHash hashFunction,
      TokenListRenderer tokenListRenderer,
      boolean deleteOldTokenLists,
      File workingDirectory,
      File outputDirectory,
      String fileNamePrefix,
      String fileNameSuffix
   ) {
      this.tokenAlphabet = tokenAlphabet;
      this.tokenLength = tokenLength;
      this.tokensPerList = tokensPerList;
      this.hashFunction = hashFunction;
      this.tokenListRenderer = tokenListRenderer;
      this.deleteOldTokenLists = deleteOldTokenLists;
      this.workingDirectory = workingDirectory;
      this.outputDirectory = outputDirectory;
      this.fileNamePrefix = fileNamePrefix;
      this.fileNameSuffix = fileNameSuffix;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class MatrixCardGeneratorConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Alphabet tokenAlphabet;
      @SuppressFBWarnings(justification = "generated code")
      private int tokenLength;
      @SuppressFBWarnings(justification = "generated code")
      private int tokensPerList;
      @SuppressFBWarnings(justification = "generated code")
      private PasswordHash hashFunction;
      @SuppressFBWarnings(justification = "generated code")
      private TokenListRenderer tokenListRenderer;
      @SuppressFBWarnings(justification = "generated code")
      private boolean deleteOldTokenLists;
      @SuppressFBWarnings(justification = "generated code")
      private File workingDirectory;
      @SuppressFBWarnings(justification = "generated code")
      private File outputDirectory;
      @SuppressFBWarnings(justification = "generated code")
      private String fileNamePrefix;
      @SuppressFBWarnings(justification = "generated code")
      private String fileNameSuffix;

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

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder tokenAlphabet(Alphabet tokenAlphabet) {
         this.tokenAlphabet = tokenAlphabet;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder tokenLength(int tokenLength) {
         this.tokenLength = tokenLength;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder tokensPerList(int tokensPerList) {
         this.tokensPerList = tokensPerList;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder hashFunction(PasswordHash hashFunction) {
         this.hashFunction = hashFunction;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder tokenListRenderer(TokenListRenderer tokenListRenderer) {
         this.tokenListRenderer = tokenListRenderer;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder deleteOldTokenLists(boolean deleteOldTokenLists) {
         this.deleteOldTokenLists = deleteOldTokenLists;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder workingDirectory(File workingDirectory) {
         this.workingDirectory = workingDirectory;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder outputDirectory(File outputDirectory) {
         this.outputDirectory = outputDirectory;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder fileNamePrefix(String fileNamePrefix) {
         this.fileNamePrefix = fileNamePrefix;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder fileNameSuffix(String fileNameSuffix) {
         this.fileNameSuffix = fileNameSuffix;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MatrixCardGeneratorConfig build() {
         return new MatrixCardGeneratorConfig(
            this.tokenAlphabet,
            this.tokenLength,
            this.tokensPerList,
            this.hashFunction,
            this.tokenListRenderer,
            this.deleteOldTokenLists,
            this.workingDirectory,
            this.outputDirectory,
            this.fileNamePrefix,
            this.fileNameSuffix
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "MatrixCardGeneratorConfig.MatrixCardGeneratorConfigBuilder(tokenAlphabet="
            + this.tokenAlphabet
            + ", tokenLength="
            + this.tokenLength
            + ", tokensPerList="
            + this.tokensPerList
            + ", hashFunction="
            + this.hashFunction
            + ", tokenListRenderer="
            + this.tokenListRenderer
            + ", deleteOldTokenLists="
            + this.deleteOldTokenLists
            + ", workingDirectory="
            + this.workingDirectory
            + ", outputDirectory="
            + this.outputDirectory
            + ", fileNamePrefix="
            + this.fileNamePrefix
            + ", fileNameSuffix="
            + this.fileNameSuffix
            + ")";
      }
   }
}
