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

import com.airlock.iam.common.application.configuration.event.AdminappSubscribedEventConfig;
import com.airlock.iam.common.domain.model.event.RemoteEventSubscriberSettings.HttpMethod;
import com.airlock.iam.common.domain.model.event.RemoteEventSubscriberSettings.ValueEncoding;
import com.airlock.iam.core.misc.util.httpclient.HttpClientConfig;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.property.EnumProperty;
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.Optional;

@Plugin(
   description = "An event subscriber that executes an HTTP request to forward the event data to a remote endpoint.",
   displayName = "Remote Event Subscriber (Adminapp)"
)
public final class AdminappRemoteEventSubscriberConfig extends AdminappGeneralEventSubscriberConfig {
   @StringProperty(
      description = "URL to which the request will be sent. The URL can contain variables (using the <tt>${variableName}</tt> notation) that will be replaced by the values provided by the event and the context-data of the managed user. See the \"Body Template\" property for a list of all available variables. All values are URL-encoded before being inserted into the URL. To ensure a successful connection the URL should include a scheme - usually either 'http' or 'https'.",
      displayName = "Remote URL",
      exampleValues = "https://my.remote.host/api/${event.data.userId}/notify",
      optional = false
   )
   private String remoteUrl;
   @StringProperty(
      description = "Template for the request body. 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. All values are encoded/escaped before being inserted into the request body.",
      isMultiLineText = true,
      optional = true,
      exampleValues = "{\"type\": \"user-locked\", \"userId\": \"${event.data.userId}\"}"
   )
   private String bodyTemplate;
   @EnumProperty(
      description = "<p>The encoding/escaping to be applied to all string values before they are inserted into the request body template.</p><p>Security warning: using no encoding allows unvalidated user input to be sent in the request body.</p><p>The JSON encoder also transforms string lists into (escaped) JSON arrays.</p>",
      defaultValue = "JSON",
      displayName = "Value Encoding/Escaping",
      optional = true
   )
   private ValueEncoding valueEncoding;
   @PluginProperty(description = "The HTTP client that executes the request.", displayName = "HTTP Client", optional = false)
   private HttpClientConfig httpClient;
   @EnumProperty(description = "HTTP Method to be used.", defaultValue = "POST", displayName = "HTTP Method", optional = true)
   private HttpMethod httpMethod;
   @StringProperty(
      description = "Value of the content-type header to be used in the request.",
      optional = true,
      suggestedValues = {"application/json", "application/x-www-form-urlencoded", "application/xml", "text/plain"},
      defaultValue = "application/json"
   )
   private String contentType;

   AdminappRemoteEventSubscriberConfig(
      AdminappSubscribedEventConfig event,
      HttpClientConfig httpClient,
      HttpMethod httpMethod,
      String remoteUrl,
      String bodyTemplate,
      ValueEncoding valueEncoding,
      String contentType
   ) {
      super(event);
      this.httpClient = httpClient;
      this.httpMethod = httpMethod;
      this.remoteUrl = remoteUrl;
      this.bodyTemplate = bodyTemplate;
      this.valueEncoding = valueEncoding;
      this.contentType = contentType;
   }

   public String getRemoteUrl() {
      return this.remoteUrl;
   }

   public Optional<String> getBodyTemplate() {
      return Optional.ofNullable(this.bodyTemplate);
   }

   public ValueEncoding getValueEncoding() {
      return this.valueEncoding;
   }

   public HttpClientConfig getHttpClient() {
      return this.httpClient;
   }

   public HttpMethod getHttpMethod() {
      return this.httpMethod;
   }

   public String getContentType() {
      return this.contentType;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class AdminappRemoteEventSubscriberConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private AdminappSubscribedEventConfig event;
      @SuppressFBWarnings(justification = "generated code")
      private HttpClientConfig httpClient;
      @SuppressFBWarnings(justification = "generated code")
      private HttpMethod httpMethod;
      @SuppressFBWarnings(justification = "generated code")
      private String remoteUrl;
      @SuppressFBWarnings(justification = "generated code")
      private String bodyTemplate;
      @SuppressFBWarnings(justification = "generated code")
      private ValueEncoding valueEncoding;
      @SuppressFBWarnings(justification = "generated code")
      private String contentType;

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

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

      @SuppressFBWarnings(justification = "generated code")
      public AdminappRemoteEventSubscriberConfig.AdminappRemoteEventSubscriberConfigBuilder httpClient(HttpClientConfig httpClient) {
         this.httpClient = httpClient;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappRemoteEventSubscriberConfig.AdminappRemoteEventSubscriberConfigBuilder httpMethod(HttpMethod httpMethod) {
         this.httpMethod = httpMethod;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappRemoteEventSubscriberConfig.AdminappRemoteEventSubscriberConfigBuilder remoteUrl(String remoteUrl) {
         this.remoteUrl = remoteUrl;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappRemoteEventSubscriberConfig.AdminappRemoteEventSubscriberConfigBuilder bodyTemplate(String bodyTemplate) {
         this.bodyTemplate = bodyTemplate;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappRemoteEventSubscriberConfig.AdminappRemoteEventSubscriberConfigBuilder valueEncoding(ValueEncoding valueEncoding) {
         this.valueEncoding = valueEncoding;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappRemoteEventSubscriberConfig.AdminappRemoteEventSubscriberConfigBuilder contentType(String contentType) {
         this.contentType = contentType;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AdminappRemoteEventSubscriberConfig build() {
         return new AdminappRemoteEventSubscriberConfig(
            this.event, this.httpClient, this.httpMethod, this.remoteUrl, this.bodyTemplate, this.valueEncoding, this.contentType
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "AdminappRemoteEventSubscriberConfig.AdminappRemoteEventSubscriberConfigBuilder(event="
            + this.event
            + ", httpClient="
            + this.httpClient
            + ", httpMethod="
            + this.httpMethod
            + ", remoteUrl="
            + this.remoteUrl
            + ", bodyTemplate="
            + this.bodyTemplate
            + ", valueEncoding="
            + this.valueEncoding
            + ", contentType="
            + this.contentType
            + ")";
      }
   }
}
