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

import com.airlock.iam.oauth2.domain.model.logging.MaskingTokenRepresentation;
import com.airlock.iam.oauth2.domain.model.logging.OAuth2TokenRepresentation;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.lifecycle.AfterConfigActivation;
import com.airlock.iam.plugin.api.annotation.property.IntegerProperty;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.Environment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.ConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.IntegerPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

@Plugin(
   displayName = "Mask Token",
   description = "Logs an excerpt of the token. The parameters must be chosen considering the 'Token Random Part Length' in the OAuth 2.0 configuration: a larger token length may allow for a larger number of characters to be logged.<p><b>Be aware</b> that logging token information is detrimental to security.</p>"
)
public final class MaskTokenLogStrategy implements OAuth2TokenLoggingStrategy {
   @IntegerProperty(description = "Number of leading characters to log.", minValue = 0, optional = false, exampleValues = {10, 16})
   private int numberOfLeadingCharacters;
   private static final String LEADING_CHARS_FIELD = "numberOfLeadingCharacters";
   @IntegerProperty(description = "Number of trailing characters to log.", minValue = 0, optional = false, exampleValues = {10, 16})
   private int numberOfTrailingCharacters;
   private static final String TRAILING_CHARS_FIELD = "numberOfTrailingCharacters";
   private OAuth2TokenRepresentation tokenRepresentation;

   public MaskTokenLogStrategy(int numberOfLeadingCharacters, int numberOfTrailingCharacters) {
      this.numberOfLeadingCharacters = numberOfLeadingCharacters;
      this.numberOfTrailingCharacters = numberOfTrailingCharacters;
   }

   @ConfigurationValidator
   public static void validate(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment) throws ConfigurationException {
      int nrOfLeadingChars = IntegerPropertyValueReader.effectiveIntegerConfigValue(config, "numberOfLeadingCharacters", env, context);
      int nrOfTrailingChars = IntegerPropertyValueReader.effectiveIntegerConfigValue(config, "numberOfTrailingCharacters", env, context);
      if (nrOfLeadingChars + nrOfTrailingChars <= 0) {
         throw new PropertyConstraintViolationException(
            "numberOfLeadingCharacters",
            config,
            env,
            context,
            "The sum of 'Number of Leading Characters' and 'Number Of Trailing Characters' must be greater than 0"
         );
      }
   }

   @AfterConfigActivation
   void initializeOAuth2LogMessageGenerator() {
      this.tokenRepresentation = MaskingTokenRepresentation.builder()
         .numberOfLeadingCharacters(this.numberOfLeadingCharacters)
         .numberOfTrailingCharacters(this.numberOfTrailingCharacters)
         .build();
   }

   @Override
   public OAuth2TokenRepresentation tokenRepresentation() {
      return this.tokenRepresentation;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class MaskTokenLogStrategyBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private int numberOfLeadingCharacters;
      @SuppressFBWarnings(justification = "generated code")
      private int numberOfTrailingCharacters;

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

      @SuppressFBWarnings(justification = "generated code")
      public MaskTokenLogStrategy.MaskTokenLogStrategyBuilder numberOfLeadingCharacters(int numberOfLeadingCharacters) {
         this.numberOfLeadingCharacters = numberOfLeadingCharacters;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MaskTokenLogStrategy.MaskTokenLogStrategyBuilder numberOfTrailingCharacters(int numberOfTrailingCharacters) {
         this.numberOfTrailingCharacters = numberOfTrailingCharacters;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MaskTokenLogStrategy build() {
         return new MaskTokenLogStrategy(this.numberOfLeadingCharacters, this.numberOfTrailingCharacters);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "MaskTokenLogStrategy.MaskTokenLogStrategyBuilder(numberOfLeadingCharacters="
            + this.numberOfLeadingCharacters
            + ", numberOfTrailingCharacters="
            + this.numberOfTrailingCharacters
            + ")";
      }
   }
}
