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

import com.airlock.iam.common.application.configuration.event.AdminappSubscribedEventConfig;
import com.airlock.iam.common.application.configuration.language.LanguageSettingsValidator;
import com.airlock.iam.common.application.configuration.mtan.BasicMtanSettings;
import com.airlock.iam.common.application.configuration.sms.PhoneNumbersProviderConfig;
import com.airlock.iam.core.application.configuration.contextdata.StringContextDataItemNameConfig;
import com.airlock.iam.core.misc.util.LanguageUtils;
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.property.PluginListProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
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.PropertyConfigurationException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;

@Plugin(description = "An event subscriber that sends an SMS to notify a user.", displayName = "SMS Event Subscriber (Adminapp)")
public final class AdminappSmsEventSubscriberConfig extends AdminappGeneralEventSubscriberConfig {
   @PluginProperty(description = "Settings to send a SMS to the notified user.", displayName = "SMS settings", optional = false)
   private BasicMtanSettings smsSettings;
   @PluginListProperty(description = "Provides the phone numbers to which the notification will be sent.", optional = false)
   private List<PhoneNumbersProviderConfig> phoneNumberProviders;
   @StringProperty(
      description = "The resource key under which the localized template for the sms message can be found. The following syntax can be used to include data in the template. <ul><li><tt>${contextDataName}</tt> for the value of <tt>contextDataName</tt> in the context-data of the managed user.</li><li><tt>${event.createdAt,date,format}</tt> for the date/time at which the event was created, where \"format\" is a date pattern like \"yyyy-MM-dd HH:mm:ss\".</li></ul>Depending on the event and on the conditions in which the event originated, the following variables may also be available: <ul><li><tt>event.createdAt</tt></li><li><tt>event.data.addedRoles</tt> (list of strings)</li><li><tt>event.data.airlock2FAAccountId</tt></li><li><tt>event.data.airlock2FADeviceId</tt></li><li><tt>event.data.activeAuthenticationMethod</tt></li><li><tt>event.data.contextDataChanged.%s.newValue</tt> (where \"%s\" is replaced by the context-data field name).</li><li><tt>event.data.contextDataChanged.%s.oldValue</tt> (where \"%s\" is replaced by the context-data field name).</li><li><tt>event.data.crontoDeviceId</tt></li><li><tt>event.data.fidoCredentialId</tt></li><li><tt>event.data.lockReason</tt></li><li><tt>event.data.mtanNewPhoneNumber</tt></li><li><tt>event.data.mtanNumberId</tt></li><li><tt>event.data.mtanOldPhoneNumber</tt></li><li><tt>event.data.newEmailAddress</tt></li><li><tt>event.data.newRoles</tt> (list of strings)</li><li><tt>event.data.oldEmailAddress</tt></li><li><tt>event.data.oldRoles</tt> (list of strings)</li><li><tt>event.data.previousAuthenticationMethod</tt></li><li><tt>event.data.removedRoles</tt> (list of strings)</li><li><tt>event.data.userId</tt></li><li><tt>event.id</tt></li><li><tt>event.metadata.requestIp</tt></li><li><tt>event.metadata.userAgent</tt></li><li><tt>event.source.adminId</tt></li></ul>Variables that are not defined are replaced by an empty string. The Airlock IAM documentation provides further information about the availability of specific variables.",
      optional = true,
      defaultValue = "sms.notification.message"
   )
   private String messageResourceKey;
   @PluginProperty(
      description = "The context data field whose value is to be used as the recipient's message language. If the provided value is blank or invalid, the default language will be used.",
      optional = false
   )
   private StringContextDataItemNameConfig languageContextDataName;
   @StringProperty(
      description = "The default language code used when no (or no valid) information about the current language is present. A corresponding locale must be available.",
      optional = true,
      defaultValue = "de",
      suggestedValues = {"de", "fr", "en"}
   )
   private String defaultLanguage;
   private static final String DEFAULT_LANGUAGE_FIELD = "defaultLanguage";

   @ConfigurationValidator
   static void checkDefaultLanguage(PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment) throws PropertyConfigurationException {
      String configuredDefaultLanguage = StringPropertyValueReader.effectiveStringConfigValue(pc, "defaultLanguage", env, context);
      LanguageSettingsValidator.ensureLocaleExists(pc, env, context, validationEnvironment, "defaultLanguage", configuredDefaultLanguage);
   }

   public AdminappSmsEventSubscriberConfig(
      AdminappSubscribedEventConfig event,
      StringContextDataItemNameConfig languageContextDataName,
      String defaultLanguage,
      BasicMtanSettings smsSettings,
      List<PhoneNumbersProviderConfig> phoneNumberProviders,
      String messageResourceKey
   ) {
      super(event);
      this.languageContextDataName = languageContextDataName;
      this.defaultLanguage = defaultLanguage;
      this.smsSettings = smsSettings;
      this.phoneNumberProviders = phoneNumberProviders;
      this.messageResourceKey = messageResourceKey;
   }

   public Locale getDefaultLocale() {
      return LanguageUtils.getLocale(this.defaultLanguage);
   }

   public BasicMtanSettings getSmsSettings() {
      return this.smsSettings;
   }

   public List<PhoneNumbersProviderConfig> getPhoneNumberProviders() {
      return this.phoneNumberProviders;
   }

   public String getMessageResourceKey() {
      return this.messageResourceKey;
   }

   public StringContextDataItemNameConfig getLanguageContextDataName() {
      return this.languageContextDataName;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class AdminappSmsEventSubscriberConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private AdminappSubscribedEventConfig event;
      @SuppressFBWarnings(justification = "generated code")
      private StringContextDataItemNameConfig languageContextDataName;
      @SuppressFBWarnings(justification = "generated code")
      private String defaultLanguage;
      @SuppressFBWarnings(justification = "generated code")
      private BasicMtanSettings smsSettings;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<PhoneNumbersProviderConfig> phoneNumberProviders;
      @SuppressFBWarnings(justification = "generated code")
      private String messageResourceKey;

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

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSmsEventSubscriberConfig.AdminappSmsEventSubscriberConfigBuilder event(AdminappSubscribedEventConfig event) {
         this.event = event;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSmsEventSubscriberConfig.AdminappSmsEventSubscriberConfigBuilder languageContextDataName(
         StringContextDataItemNameConfig languageContextDataName
      ) {
         this.languageContextDataName = languageContextDataName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSmsEventSubscriberConfig.AdminappSmsEventSubscriberConfigBuilder defaultLanguage(String defaultLanguage) {
         this.defaultLanguage = defaultLanguage;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSmsEventSubscriberConfig.AdminappSmsEventSubscriberConfigBuilder smsSettings(BasicMtanSettings smsSettings) {
         this.smsSettings = smsSettings;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSmsEventSubscriberConfig.AdminappSmsEventSubscriberConfigBuilder phoneNumberProvider(PhoneNumbersProviderConfig phoneNumberProvider) {
         if (this.phoneNumberProviders == null) {
            this.phoneNumberProviders = new ArrayList<>();
         }

         this.phoneNumberProviders.add(phoneNumberProvider);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSmsEventSubscriberConfig.AdminappSmsEventSubscriberConfigBuilder phoneNumberProviders(
         Collection<? extends PhoneNumbersProviderConfig> phoneNumberProviders
      ) {
         if (phoneNumberProviders == null) {
            throw new NullPointerException("phoneNumberProviders cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSmsEventSubscriberConfig.AdminappSmsEventSubscriberConfigBuilder clearPhoneNumberProviders() {
         if (this.phoneNumberProviders != null) {
            this.phoneNumberProviders.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSmsEventSubscriberConfig.AdminappSmsEventSubscriberConfigBuilder messageResourceKey(String messageResourceKey) {
         this.messageResourceKey = messageResourceKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappSmsEventSubscriberConfig build() {
         return new AdminappSmsEventSubscriberConfig(
            this.event,
            this.languageContextDataName,
            this.defaultLanguage,
            this.smsSettings,
            switch (this.phoneNumberProviders == null ? 0 : this.phoneNumberProviders.size()) {
               case 0 -> Collections.emptyList();
               case 1 -> Collections.singletonList(this.phoneNumberProviders.get(0));
               default -> Collections.unmodifiableList(new ArrayList<>(this.phoneNumberProviders));
            },
            this.messageResourceKey
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "AdminappSmsEventSubscriberConfig.AdminappSmsEventSubscriberConfigBuilder(event="
            + this.event
            + ", languageContextDataName="
            + this.languageContextDataName
            + ", defaultLanguage="
            + this.defaultLanguage
            + ", smsSettings="
            + this.smsSettings
            + ", phoneNumberProviders="
            + this.phoneNumberProviders
            + ", messageResourceKey="
            + this.messageResourceKey
            + ")";
      }
   }
}
