package com.airlock.iam.oauth2.application.configuration.client;

import com.airlock.iam.common.api.application.configuration.location.transform.StringTransformerConfig;
import com.airlock.iam.common.domain.model.transform.TransformationProcessor;
import com.airlock.iam.oauth2.domain.service.client.resource.OAuth2RemoteContextDataResourceLogic;
import com.airlock.iam.oauth2.domain.service.client.resource.OAuth2RemoteResource;
import com.airlock.iam.oauth2.domain.service.client.resource.OAuth2ResourceSelector;
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.StringProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Plugin(
   description = "Extracts a single value from a remote resource. The value will finally be available in the authentee's context data.",
   displayName = "OAuth 2.0 Remote Context Data Resource"
)
@PluginLicenseRestriction(moduleAffiliation = "OAuthClient")
public final class OAuth2RemoteContextDataResource extends AbstractOAuth2RemoteResourceConfig {
   public static final String OAUTH2_REMOTE_CONTEXT_DATA_RESOURCE_DISPLAY_NAME = "OAuth 2.0 Remote Context Data Resource";
   public static final String LOCAL_CONTEXT_DATA_KEY_DISPLAY_NAME = "Local Context Data Key";
   @StringProperty(
      description = "The key used to store this data item in the authentee's context data.",
      displayName = "Local Context Data Key",
      optional = false
   )
   private String localContextDataKey;
   @BooleanProperty(
      description = "If set to false, the resource must be present. In case the resource cannot be obtained, authentication fails. <br/> If set to true, the authentee's context data field is only set in case the resource is present. In case the resource cannot be obtained, the context data field will not be added to the authentee.",
      optional = true,
      defaultValue = "false"
   )
   private boolean optional;
   @PluginListProperty(
      description = "If the selected resource is a string value, a chain of string transformers may be specified to transform the selected resource.<br/>Note: If the resource is not a string, but a list of string transformers is configured, authentication fails.",
      optional = true,
      minElements = 1
   )
   private List<StringTransformerConfig> stringTransformers;

   public OAuth2RemoteContextDataResource(
      OAuth2ResourceSelector resourceSelector, String localContextDataKey, boolean optional, List<StringTransformerConfig> stringTransformers
   ) {
      super(resourceSelector);
      this.localContextDataKey = localContextDataKey;
      this.optional = optional;
      this.stringTransformers = stringTransformers == null ? Collections.emptyList() : stringTransformers.stream().collect(Collectors.toUnmodifiableList());
   }

   @Override
   public OAuth2RemoteResource resource() {
      return new OAuth2RemoteContextDataResourceLogic(this.localContextDataKey, this.optional, this.getResourceSelector(), this.stringTransformationProcessor());
   }

   private Optional<TransformationProcessor<String>> stringTransformationProcessor() {
      return this.stringTransformers.isEmpty()
         ? Optional.empty()
         : Optional.of(new TransformationProcessor<>(this.stringTransformers.stream().map(StringTransformerConfig::getLogic).collect(Collectors.toList())));
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class OAuth2RemoteContextDataResourceBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private OAuth2ResourceSelector resourceSelector;
      @SuppressFBWarnings(justification = "generated code")
      private String localContextDataKey;
      @SuppressFBWarnings(justification = "generated code")
      private boolean optional;
      @SuppressFBWarnings(justification = "generated code")
      private List<StringTransformerConfig> stringTransformers;

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

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2RemoteContextDataResource.OAuth2RemoteContextDataResourceBuilder resourceSelector(OAuth2ResourceSelector resourceSelector) {
         this.resourceSelector = resourceSelector;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2RemoteContextDataResource.OAuth2RemoteContextDataResourceBuilder localContextDataKey(String localContextDataKey) {
         this.localContextDataKey = localContextDataKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2RemoteContextDataResource.OAuth2RemoteContextDataResourceBuilder optional(boolean optional) {
         this.optional = optional;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2RemoteContextDataResource.OAuth2RemoteContextDataResourceBuilder stringTransformers(List<StringTransformerConfig> stringTransformers) {
         this.stringTransformers = stringTransformers;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public OAuth2RemoteContextDataResource build() {
         return new OAuth2RemoteContextDataResource(this.resourceSelector, this.localContextDataKey, this.optional, this.stringTransformers);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "OAuth2RemoteContextDataResource.OAuth2RemoteContextDataResourceBuilder(resourceSelector="
            + this.resourceSelector
            + ", localContextDataKey="
            + this.localContextDataKey
            + ", optional="
            + this.optional
            + ", stringTransformers="
            + this.stringTransformers
            + ")";
      }
   }
}
