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

import com.airlock.iam.core.misc.cronto.CrontoHandler;
import com.airlock.iam.flow.api.application.configuration.valueprovider.ValueMapProviderConfig;
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.PluginListProperty;
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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

@Plugin(description = "Generic provider for Cronto messages.", displayName = "Cronto Message Provider")
@PluginLicenseRestriction(moduleAffiliation = "Cronto")
public class GenericCrontoMessageProviderConfig implements GenericCrontoMessageProviderConfigSpec {
   @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 the same formatting options (including shrinking of values to fit to limited size) as are available for Transaction Approval messages.",
      exampleValues = {"self-service.user-data-edit.approval.cronto", "password-reset.factors.cronto.message"},
      optional = false
   )
   private String resourceKey;
   @StringProperty(
      description = "Resource key to select the localized template to display the push title. The localized template can contain variables (e.g. <tt>${username}</tt>).",
      exampleValues = "cronto.push.login.title",
      defaultValue = "cronto.push.login.title",
      optional = true
   )
   private String pushTitleResourceKey;
   @StringProperty(
      description = "Resource key to select the localized template to display the push subject. The localized template can contain variables (e.g. <tt>${username}</tt>).",
      exampleValues = "cronto.push.login.subject",
      defaultValue = "cronto.push.login.subject",
      optional = true
   )
   private String pushSubjectResourceKey;
   @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. If available, the \"Login ID\" is provided under the key \" login-id\".",
      optional = true
   )
   private List<ValueMapProviderConfig> valueProviders;
   @BooleanProperty(
      description = "If enabled, lines with an empty or blank \"value\" part (right-hand side) after variable replacing are omitted from the message. Example: if the message contains a line <tt>Town=${town}</tt> and the \"town\" variable is empty, then the whole line will be omitted.",
      optional = true,
      defaultValue = "false"
   )
   private boolean omitEmptyValueLines;
   @PluginProperty(
      description = "Cronto Handler to determine if a message is small enough to be encoded as a cryptogram. This is used for \"shrinking\" the growable message until it fits into a cryptogram. If it cannot be shrunk enough, an exception is thrown.",
      globalPluginReference = "globalCrontoSettings",
      optional = false
   )
   private CrontoHandler crontoHandler;

   @Override
   public String getMessageResourceKey() {
      return this.resourceKey;
   }

   public String getPushTitleResourceKey() {
      return this.pushTitleResourceKey;
   }

   public String getPushSubjectResourceKey() {
      return this.pushSubjectResourceKey;
   }

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

   @Override
   public boolean isOmitEmptyValueLines() {
      return this.omitEmptyValueLines;
   }

   @Override
   public CrontoHandler getCrontoHandler() {
      return this.crontoHandler;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public GenericCrontoMessageProviderConfig(
      String resourceKey,
      String pushTitleResourceKey,
      String pushSubjectResourceKey,
      List<ValueMapProviderConfig> valueProviders,
      boolean omitEmptyValueLines,
      CrontoHandler crontoHandler
   ) {
      this.resourceKey = resourceKey;
      this.pushTitleResourceKey = pushTitleResourceKey;
      this.pushSubjectResourceKey = pushSubjectResourceKey;
      this.valueProviders = valueProviders;
      this.omitEmptyValueLines = omitEmptyValueLines;
      this.crontoHandler = crontoHandler;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class GenericCrontoMessageProviderConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String resourceKey;
      @SuppressFBWarnings(justification = "generated code")
      private String pushTitleResourceKey;
      @SuppressFBWarnings(justification = "generated code")
      private String pushSubjectResourceKey;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<ValueMapProviderConfig> valueProviders;
      @SuppressFBWarnings(justification = "generated code")
      private boolean omitEmptyValueLines;
      @SuppressFBWarnings(justification = "generated code")
      private CrontoHandler crontoHandler;

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

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

      @SuppressFBWarnings(justification = "generated code")
      public GenericCrontoMessageProviderConfig.GenericCrontoMessageProviderConfigBuilder pushTitleResourceKey(String pushTitleResourceKey) {
         this.pushTitleResourceKey = pushTitleResourceKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericCrontoMessageProviderConfig.GenericCrontoMessageProviderConfigBuilder pushSubjectResourceKey(String pushSubjectResourceKey) {
         this.pushSubjectResourceKey = pushSubjectResourceKey;
         return this;
      }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public GenericCrontoMessageProviderConfig.GenericCrontoMessageProviderConfigBuilder 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 GenericCrontoMessageProviderConfig.GenericCrontoMessageProviderConfigBuilder clearValueProviders() {
         if (this.valueProviders != null) {
            this.valueProviders.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericCrontoMessageProviderConfig.GenericCrontoMessageProviderConfigBuilder omitEmptyValueLines(boolean omitEmptyValueLines) {
         this.omitEmptyValueLines = omitEmptyValueLines;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericCrontoMessageProviderConfig.GenericCrontoMessageProviderConfigBuilder crontoHandler(CrontoHandler crontoHandler) {
         this.crontoHandler = crontoHandler;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericCrontoMessageProviderConfig build() {
         return new GenericCrontoMessageProviderConfig(
            this.resourceKey, this.pushTitleResourceKey, this.pushSubjectResourceKey, 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.omitEmptyValueLines, this.crontoHandler
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "GenericCrontoMessageProviderConfig.GenericCrontoMessageProviderConfigBuilder(resourceKey="
            + this.resourceKey
            + ", pushTitleResourceKey="
            + this.pushTitleResourceKey
            + ", pushSubjectResourceKey="
            + this.pushSubjectResourceKey
            + ", valueProviders="
            + this.valueProviders
            + ", omitEmptyValueLines="
            + this.omitEmptyValueLines
            + ", crontoHandler="
            + this.crontoHandler
            + ")";
      }
   }
}
