package com.airlock.iam.flow.shared.application.configuration.message;

import com.airlock.iam.flow.api.application.configuration.valueprovider.ValueMapProviderConfig;
import com.airlock.iam.flow.shared.api.application.configuration.message.MtanMessageProviderConfig;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.property.IntegerProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginListProperty;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

@Plugin(description = "Generic provider for mTAN messages.", displayName = "mTAN Message Provider")
public class GenericMtanMessageProviderConfig implements MtanMessageProviderConfig {
   private static final String TOKEN_PLACEHOLDER = "${TOKEN}";
   @StringProperty(
      description = "Resource key to select the localized template to display the data. The localized template can contain variables (e.g. <tt>${town}</tt>) and supports the same formatting options (including shrinking of values to fit to limited size) as are available for Transaction Approval messages. The template must contain the variable ${TOKEN} which will be replaced by the OTP token.",
      exampleValues = {"self-service.user-data-edit.approval.mtan", "password-reset.factors.mtan.message", "mtan-registration.verification.message"},
      optional = false
   )
   private String resourceKey;
   @PluginListProperty(
      description = "List of value map providers that are used to replace the variables in the localized template. The values providers are called in the configured order and their values are added to a map. Later providers can overwrite values from earlier providers. If no value providers are configured, the localized template should not contain any variables, since all of them would be replaced by empty strings. The OTP token for the ${TOKEN} variable is always added to the map and doesn't have to be configured here.",
      optional = true
   )
   private List<ValueMapProviderConfig> valueProviders;
   @IntegerProperty(
      description = "Defines the maximum length for the mTAN message. If the message cannot be fit into this length (potentially after shrinking values), an exception is thrown.",
      optional = true,
      defaultValue = 160,
      displayName = "Maximum Message Length",
      exampleValues = {100, 120, 140}
   )
   private int maxLength;

   public String getResourceKey() {
      return this.resourceKey;
   }

   public List<ValueMapProviderConfig> getValueProviders() {
      return this.valueProviders;
   }

   public int getMaxLength() {
      return this.maxLength;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public GenericMtanMessageProviderConfig(String resourceKey, List<ValueMapProviderConfig> valueProviders, int maxLength) {
      this.resourceKey = resourceKey;
      this.valueProviders = valueProviders;
      this.maxLength = maxLength;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class GenericMtanMessageProviderConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String resourceKey;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<ValueMapProviderConfig> valueProviders;
      @SuppressFBWarnings(justification = "generated code")
      private int maxLength;

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

      @SuppressFBWarnings(justification = "generated code")
      public GenericMtanMessageProviderConfig.GenericMtanMessageProviderConfigBuilder resourceKey(String resourceKey) {
         this.resourceKey = resourceKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericMtanMessageProviderConfig.GenericMtanMessageProviderConfigBuilder valueProvider(ValueMapProviderConfig valueProvider) {
         if (this.valueProviders == null) {
            this.valueProviders = new ArrayList<>();
         }

         this.valueProviders.add(valueProvider);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericMtanMessageProviderConfig.GenericMtanMessageProviderConfigBuilder valueProviders(
         Collection<? extends ValueMapProviderConfig> valueProviders
      ) {
         if (valueProviders == null) {
            throw new NullPointerException("valueProviders cannot be null");
         }

         if (this.valueProviders == null) {
            this.valueProviders = new ArrayList<>();
         }

         this.valueProviders.addAll(valueProviders);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericMtanMessageProviderConfig.GenericMtanMessageProviderConfigBuilder clearValueProviders() {
         if (this.valueProviders != null) {
            this.valueProviders.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericMtanMessageProviderConfig.GenericMtanMessageProviderConfigBuilder maxLength(int maxLength) {
         this.maxLength = maxLength;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericMtanMessageProviderConfig build() {
         return new GenericMtanMessageProviderConfig(this.resourceKey, switch (this.valueProviders == null ? 0 : this.valueProviders.size()) {
            case 0 -> Collections.emptyList();
            case 1 -> Collections.singletonList(this.valueProviders.get(0));
            default -> Collections.unmodifiableList(new ArrayList<>(this.valueProviders));
         }, this.maxLength);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "GenericMtanMessageProviderConfig.GenericMtanMessageProviderConfigBuilder(resourceKey="
            + this.resourceKey
            + ", valueProviders="
            + this.valueProviders
            + ", maxLength="
            + this.maxLength
            + ")";
      }
   }
}
