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

import com.airlock.iam.common.api.application.configuration.valueprovider.StringValueProviderConfig;
import com.airlock.iam.common.api.domain.service.email.EmailService;
import com.airlock.iam.common.application.configuration.event.EventEmailRecipientConfig;
import com.airlock.iam.common.application.configuration.event.LoginappSubscribedEventConfig;
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.property.BooleanProperty;
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 = "An event subscriber that sends an email to notify a user.", displayName = "Email Event Subscriber (Loginapp)")
public final class LoginappEmailEventSubscriberConfig extends LoginappGeneralEventSubscriberConfig {
   @PluginProperty(description = "Email service for sending emails.", displayName = "Email Service", optional = false)
   private EmailService emailService;
   @PluginProperty(description = "Email address to which the notification email is sent.", optional = false)
   private EventEmailRecipientConfig.LoginappEventEmailRecipientConfig recipientAddress;
   @StringProperty(
      description = "The resource key under which the localized template for the email subject can be found. The following syntax can be used to include data in the template. <ul><li><tt>${valueMapKey}</tt> for the value of <tt>valueMapKey</tt> provided by any of the configured Value Map Providers.</li><li><tt>${event.createdAt,date,format}</tt> to include 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.airlock2FAAccountId</tt></li><li><tt>event.data.airlock2FADeviceId</tt></li><li><tt>event.data.activeAuthenticationMethod</tt></li><li><tt>event.data.authenticationMethods</tt></li><li><tt>event.data.browser</tt></li><li><tt>event.data.city</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.countryCode</tt></li><li><tt>event.data.crontoDeviceId</tt></li><li><tt>event.data.device</tt></li><li><tt>event.data.deviceTokenId</tt></li><li><tt>event.data.fidoCredentialId</tt></li><li><tt>event.data.fidoPublicKeyCredentialId</tt></li><li><tt>event.data.oauth2.authorizationServerId</tt></li><li><tt>event.data.fidoRelyingPartyId</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.oauth2.acceptedScopes</tt></li><li><tt>event.data.oauth2.alwaysGrantedScopes</tt></li><li><tt>event.data.oauth2.clientId</tt></li><li><tt>event.data.oauth2.deniedScopes</tt></li><li><tt>event.data.oldEmailAddress</tt></li><li><tt>event.data.operatingSystem</tt></li><li><tt>event.data.previousAuthenticationMethod</tt></li><li><tt>event.data.stepResult.attributes.&lt;attribute-name&gt;</tt> (where &lt;attribute-name&gt ist the name of the additional attribute, could be nested.)</li><li><tt>event.data.stepResult.errorCode</tt></li><li><tt>event.data.stepResult.nextAction</tt></li><li><tt>event.data.stepResult.type</tt></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.applicationId</tt></li><li><tt>event.source.configurationContext</tt></li><li><tt>event.source.flowId</tt></li><li><tt>event.source.stepId</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,
      suggestedValues = {
            "email.notification.address-changed-event.subject",
            "email.notification.airlock2fa-device-activated-event.subject",
            "email.notification.airlock2fa-device-deleted-event.subject",
            "email.notification.airlock2fa-device-in-cooldown-used-event.subject",
            "email.notification.authentication-flow-successfully-completed-event.subject",
            "email.notification.authentication-method-changed-event.subject",
            "email.notification.cronto-device-activated-event.subject",
            "email.notification.cronto-device-deleted-event.subject",
            "email.notification.cronto-letter-ordered-event.subject",
            "email.notification.device-token-deleted-event.subject",
            "email.notification.device-token-registered-event.subject",
            "email.notification.email-added-event.subject",
            "email.notification.email-changed-event.subject",
            "email.notification.email-deleted-event.subject",
            "email.notification.fido-credential-deleted-event.subject",
            "email.notification.fido-credential-registered-event.subject",
            "email.notification.login-from-new-device-event.subject",
            "email.notification.mtan-token-deleted-event.subject",
            "email.notification.mtan-token-phone-number-changed-event.subject",
            "email.notification.mtan-token-registered-event.subject",
            "email.notification.password-changed-event.subject",
            "email.notification.password-letter-ordered-event.subject",
            "email.notification.user-created-event.subject",
            "email.notification.user-locked-event.subject",
            "email.notification.user-unlocked-event.subject",
            "email.notification.oath-otp-secret-added-event.subject",
            "email.notification.oath-otp-secret-viewed-event.subject",
            "email.notification.oauth2-user-consent-event.subject"
      },
      defaultValue = "email.notification.subject"
   )
   private String subjectResourceKey;
   @StringProperty(
      description = "The resource key under which the localized template for the email message body can be found. The following syntax can be used to include data in the template. <ul><li><tt>${valueMapKey}</tt> for the value of <tt>valueMapKey</tt> provided by any of the configured Value Map Providers.</li><li><tt>${event.createdAt,date,format}</tt> to include 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.airlock2FAAccountId</tt></li><li><tt>event.data.airlock2FADeviceId</tt></li><li><tt>event.data.activeAuthenticationMethod</tt></li><li><tt>event.data.authenticationMethods</tt></li><li><tt>event.data.browser</tt></li><li><tt>event.data.city</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.countryCode</tt></li><li><tt>event.data.crontoDeviceId</tt></li><li><tt>event.data.device</tt></li><li><tt>event.data.deviceTokenId</tt></li><li><tt>event.data.fidoCredentialId</tt></li><li><tt>event.data.fidoPublicKeyCredentialId</tt></li><li><tt>event.data.oauth2.authorizationServerId</tt></li><li><tt>event.data.fidoRelyingPartyId</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.oauth2.acceptedScopes</tt></li><li><tt>event.data.oauth2.alwaysGrantedScopes</tt></li><li><tt>event.data.oauth2.clientId</tt></li><li><tt>event.data.oauth2.deniedScopes</tt></li><li><tt>event.data.oldEmailAddress</tt></li><li><tt>event.data.operatingSystem</tt></li><li><tt>event.data.previousAuthenticationMethod</tt></li><li><tt>event.data.stepResult.attributes.&lt;attribute-name&gt;</tt> (where &lt;attribute-name&gt ist the name of the additional attribute, could be nested.)</li><li><tt>event.data.stepResult.errorCode</tt></li><li><tt>event.data.stepResult.nextAction</tt></li><li><tt>event.data.stepResult.type</tt></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.applicationId</tt></li><li><tt>event.source.configurationContext</tt></li><li><tt>event.source.flowId</tt></li><li><tt>event.source.stepId</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,
      suggestedValues = {
            "email.notification.address-changed-event.body",
            "email.notification.airlock2fa-device-activated-event.body",
            "email.notification.airlock2fa-device-deleted-event.body",
            "email.notification.airlock2fa-device-in-cooldown-used-event.body",
            "email.notification.authentication-flow-successfully-completed-event.body",
            "email.notification.authentication-method-changed-event.body",
            "email.notification.cronto-device-activated-event.body",
            "email.notification.cronto-device-deleted-event.body",
            "email.notification.cronto-letter-ordered-event.body",
            "email.notification.device-token-deleted-event.body",
            "email.notification.device-token-registered-event.body",
            "email.notification.email-added-event.body",
            "email.notification.email-changed-event.body",
            "email.notification.email-deleted-event.body",
            "email.notification.fido-credential-deleted-event.body",
            "email.notification.fido-credential-registered-event.body",
            "email.notification.login-from-new-device-event.body",
            "email.notification.mtan-token-deleted-event.body",
            "email.notification.mtan-token-phone-number-changed-event.body",
            "email.notification.mtan-token-registered-event.body",
            "email.notification.oath-otp-secret-added-event.body",
            "email.notification.oath-otp-secret-viewed-event.body",
            "email.notification.password-changed-event.body",
            "email.notification.password-letter-ordered-event.body",
            "email.notification.user-created-event.body",
            "email.notification.user-locked-event.body",
            "email.notification.user-unlocked-event.body",
            "email.notification.oath-otp-secret-added-event.body",
            "email.notification.oath-otp-secret-viewed-event.body",
            "email.notification.oauth2-user-consent-event.body"
      },
      defaultValue = "email.notification.body"
   )
   private String bodyResourceKey;
   @BooleanProperty(
      description = "If enabled, the notification email will be sent as an HTML mail. Otherwise it will be sent as plain text.",
      displayName = "Send As HTML",
      optional = true,
      defaultValue = "false"
   )
   private boolean sendAsHtml;
   @PluginProperty(
      description = "A String Value Provider which provides the language of the message. It is recommended to use a context data field and not the display language, as latter could be misused by an attacker to confuse the victim with an unknown language.",
      optional = false
   )
   private StringValueProviderConfig language;

   LoginappEmailEventSubscriberConfig(
      LoginappSubscribedEventConfig event,
      List<ValueMapProviderConfig> valueMapProviders,
      EmailService emailService,
      EventEmailRecipientConfig.LoginappEventEmailRecipientConfig recipientAddress,
      String subjectResourceKey,
      String bodyResourceKey,
      boolean sendAsHtml,
      StringValueProviderConfig language
   ) {
      super(event, valueMapProviders);
      this.emailService = emailService;
      this.recipientAddress = recipientAddress;
      this.subjectResourceKey = subjectResourceKey;
      this.bodyResourceKey = bodyResourceKey;
      this.sendAsHtml = sendAsHtml;
      this.language = language;
   }

   public EmailService getEmailService() {
      return this.emailService;
   }

   public EventEmailRecipientConfig.LoginappEventEmailRecipientConfig getRecipientAddress() {
      return this.recipientAddress;
   }

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

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

   public boolean isSendAsHtml() {
      return this.sendAsHtml;
   }

   public StringValueProviderConfig getLanguage() {
      return this.language;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class LoginappEmailEventSubscriberConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private LoginappSubscribedEventConfig event;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<ValueMapProviderConfig> valueMapProviders;
      @SuppressFBWarnings(justification = "generated code")
      private EmailService emailService;
      @SuppressFBWarnings(justification = "generated code")
      private EventEmailRecipientConfig.LoginappEventEmailRecipientConfig recipientAddress;
      @SuppressFBWarnings(justification = "generated code")
      private String subjectResourceKey;
      @SuppressFBWarnings(justification = "generated code")
      private String bodyResourceKey;
      @SuppressFBWarnings(justification = "generated code")
      private boolean sendAsHtml;
      @SuppressFBWarnings(justification = "generated code")
      private StringValueProviderConfig language;

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

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEmailEventSubscriberConfig.LoginappEmailEventSubscriberConfigBuilder event(LoginappSubscribedEventConfig event) {
         this.event = event;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEmailEventSubscriberConfig.LoginappEmailEventSubscriberConfigBuilder valueMapProvider(ValueMapProviderConfig valueMapProvider) {
         if (this.valueMapProviders == null) {
            this.valueMapProviders = new ArrayList<>();
         }

         this.valueMapProviders.add(valueMapProvider);
         return this;
      }

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEmailEventSubscriberConfig.LoginappEmailEventSubscriberConfigBuilder clearValueMapProviders() {
         if (this.valueMapProviders != null) {
            this.valueMapProviders.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEmailEventSubscriberConfig.LoginappEmailEventSubscriberConfigBuilder emailService(EmailService emailService) {
         this.emailService = emailService;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEmailEventSubscriberConfig.LoginappEmailEventSubscriberConfigBuilder recipientAddress(
         EventEmailRecipientConfig.LoginappEventEmailRecipientConfig recipientAddress
      ) {
         this.recipientAddress = recipientAddress;
         return this;
      }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEmailEventSubscriberConfig.LoginappEmailEventSubscriberConfigBuilder sendAsHtml(boolean sendAsHtml) {
         this.sendAsHtml = sendAsHtml;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEmailEventSubscriberConfig.LoginappEmailEventSubscriberConfigBuilder language(StringValueProviderConfig language) {
         this.language = language;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LoginappEmailEventSubscriberConfig build() {
         return new LoginappEmailEventSubscriberConfig(this.event, switch (this.valueMapProviders == null ? 0 : this.valueMapProviders.size()) {
            case 0 -> Collections.emptyList();
            case 1 -> Collections.singletonList(this.valueMapProviders.get(0));
            default -> Collections.unmodifiableList(new ArrayList<>(this.valueMapProviders));
         }, this.emailService, this.recipientAddress, this.subjectResourceKey, this.bodyResourceKey, this.sendAsHtml, this.language);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "LoginappEmailEventSubscriberConfig.LoginappEmailEventSubscriberConfigBuilder(event="
            + this.event
            + ", valueMapProviders="
            + this.valueMapProviders
            + ", emailService="
            + this.emailService
            + ", recipientAddress="
            + this.recipientAddress
            + ", subjectResourceKey="
            + this.subjectResourceKey
            + ", bodyResourceKey="
            + this.bodyResourceKey
            + ", sendAsHtml="
            + this.sendAsHtml
            + ", language="
            + this.language
            + ")";
      }
   }
}
