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.EmailMessageProviderConfig;
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.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 message provider for emails.", displayName = "Email Message Provider")
public class GenericEmailMessageProviderConfig implements EmailMessageProviderConfig {
   @StringProperty(
      description = "Resource key to select the localized template to generate the subject line. The localized template can contain variables (e.g. <tt>${town}</tt>).",
      exampleValues = {"authentication.email.otp.subject", "user-self-reg.email.verification.subject"},
      optional = false
   )
   private String subjectResourceKey;
   @StringProperty(
      description = "Resource key to select the localized template to generate the email body. The localized template can contain variables (e.g. <tt>${town}</tt>). If the email is used to send an email OTP, the template must contain the variable ${TOKEN} which will be replaced by the OTP token.",
      exampleValues = {"authentication.email.otp.body", "user-self-reg.email.verification.body-with-otp"},
      optional = false
   )
   private String bodyResourceKey;
   @PluginListProperty(
      description = "<p>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.</p><p>If available, the OTP token for the ${TOKEN} variable is automatically added to the map and doesn't have to be configured here.</p><p><strong>Security Warning</strong>: If e-mails are sent as HTML, make sure to properly escape values originating from untrusted sources (such as user input during self-registration). This can be achieved by enabling the property 'Escape Values in HTML'. <p>If a more fine-grained control is required, use a 'Transforming Value Map Provider' with an 'HTML String Escaper' to transform all values of the map. (Alternatively, if you want to transform only individual values of a map, use a 'Value Provider Map' with 'Transforming String Value Providers'.)</p>",
      optional = true
   )
   private List<ValueMapProviderConfig> valueProviders;
   @BooleanProperty(
      description = "<p>HTML-escape all provided values if this message provider is used in an HTML email.</p><p><strong>Security Warning</strong>: If e-mails are sent as HTML, make sure to properly escape values originating from untrusted sources (such as user input during self-registration). This can be achieved by enabling the property 'Escape Values in HTML'. <p>If a more fine-grained control is required, use a 'Transforming Value Map Provider' with an 'HTML String Escaper' to transform all values of the map. (Alternatively, if you want to transform only individual values of a map, use a 'Value Provider Map' with 'Transforming String Value Providers'.)</p>",
      displayName = "Escape Values in HTML",
      defaultValue = "true",
      optional = true
   )
   private boolean escapeValuesInHtml;

   public String getSubjectResourceKey() {
      return this.subjectResourceKey;
   }

   public String getBodyResourceKey() {
      return this.bodyResourceKey;
   }

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

   public boolean isEscapeValuesInHtml() {
      return this.escapeValuesInHtml;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public GenericEmailMessageProviderConfig(
      String subjectResourceKey, String bodyResourceKey, List<ValueMapProviderConfig> valueProviders, boolean escapeValuesInHtml
   ) {
      this.subjectResourceKey = subjectResourceKey;
      this.bodyResourceKey = bodyResourceKey;
      this.valueProviders = valueProviders;
      this.escapeValuesInHtml = escapeValuesInHtml;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class GenericEmailMessageProviderConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String subjectResourceKey;
      @SuppressFBWarnings(justification = "generated code")
      private String bodyResourceKey;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<ValueMapProviderConfig> valueProviders;
      @SuppressFBWarnings(justification = "generated code")
      private boolean escapeValuesInHtml;

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

      @SuppressFBWarnings(justification = "generated code")
      public GenericEmailMessageProviderConfig.GenericEmailMessageProviderConfigBuilder subjectResourceKey(String subjectResourceKey) {
         this.subjectResourceKey = subjectResourceKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericEmailMessageProviderConfig.GenericEmailMessageProviderConfigBuilder bodyResourceKey(String bodyResourceKey) {
         this.bodyResourceKey = bodyResourceKey;
         return this;
      }

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

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

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

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericEmailMessageProviderConfig.GenericEmailMessageProviderConfigBuilder escapeValuesInHtml(boolean escapeValuesInHtml) {
         this.escapeValuesInHtml = escapeValuesInHtml;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GenericEmailMessageProviderConfig build() {
         return new GenericEmailMessageProviderConfig(
            this.subjectResourceKey, this.bodyResourceKey, 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.escapeValuesInHtml
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "GenericEmailMessageProviderConfig.GenericEmailMessageProviderConfigBuilder(subjectResourceKey="
            + this.subjectResourceKey
            + ", bodyResourceKey="
            + this.bodyResourceKey
            + ", valueProviders="
            + this.valueProviders
            + ", escapeValuesInHtml="
            + this.escapeValuesInHtml
            + ")";
      }
   }
}
