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

import com.airlock.iam.flow.ui.application.configuration.OnCompletedRedirectTargetConfig;
import com.airlock.iam.flow.ui.application.configuration.PublicFlowRedirectTargetConfig;
import com.airlock.iam.flow.ui.application.configuration.PublicSelfServiceLinkConfig;
import com.airlock.iam.flow.ui.application.configuration.RedirectTargetConfig;
import com.airlock.iam.flow.ui.application.configuration.UserSelfRegLinkConfig;
import com.airlock.iam.login.api.application.configuration.location.propagate.IdentityPropagatorURITransformerConfig;
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.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.ConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

@Plugin(
   description = "Defines an URI that can modified using transformers. The resulting URI is used as redirect target after completing a flow.",
   displayName = "Redirect to URI"
)
public class ExternalTargetUriConfig
   implements PublicFlowRedirectTargetConfig,
   OnCompletedRedirectTargetConfig,
   RedirectTargetConfig,
   UserSelfRegLinkConfig,
   PublicSelfServiceLinkConfig {
   @StringProperty(
      description = "The URI to be redirected to (after applying the URI Transformers). Must result in a valid URI that is absolute or relative to the host.",
      displayName = "Target URI",
      exampleValues = {"https://my-ebanking.ch", "/ebanking"},
      optional = false
   )
   private String targetUri;
   private static final String TARGET_URI_FIELD = "targetUri";
   private static final String TARGET_URI_DISPLAY_NAME = "Target URI";
   @PluginListProperty(
      description = "The chain of URI transformers to transform the Target URI. The transformers are applied in the configured order. If any transformer produces a 'veto', the untransformed Target URI is used.",
      displayName = "URI Transformers",
      optional = true,
      minElements = 1
   )
   private List<IdentityPropagatorURITransformerConfig> uriTransformers;
   private static final String URI_TRANSFORMERS_DISPLAY_NAME = "URI Transformers";

   @ConfigurationValidator
   static void checkDefaultValue(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment) throws ConfigurationException {
      String defaultValue = StringPropertyValueReader.effectiveStringConfigValue(config, "targetUri", env, context);

      try {
         new URI(defaultValue);
      } catch (URISyntaxException e) {
         throw new PropertyConstraintViolationException("targetUri", config, env, context, "The Target URI must be a valid URI", e);
      }
   }

   public String getTargetUri() {
      return this.targetUri;
   }

   public List<IdentityPropagatorURITransformerConfig> getUriTransformers() {
      return this.uriTransformers;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public ExternalTargetUriConfig(String targetUri, List<IdentityPropagatorURITransformerConfig> uriTransformers) {
      this.targetUri = targetUri;
      this.uriTransformers = uriTransformers;
   }

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

   @SuppressFBWarnings(justification = "generated code")
   public static class ExternalTargetUriConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String targetUri;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<IdentityPropagatorURITransformerConfig> uriTransformers;

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

      @SuppressFBWarnings(justification = "generated code")
      public ExternalTargetUriConfig.ExternalTargetUriConfigBuilder targetUri(String targetUri) {
         this.targetUri = targetUri;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExternalTargetUriConfig.ExternalTargetUriConfigBuilder uriTransformer(IdentityPropagatorURITransformerConfig uriTransformer) {
         if (this.uriTransformers == null) {
            this.uriTransformers = new ArrayList<>();
         }

         this.uriTransformers.add(uriTransformer);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExternalTargetUriConfig.ExternalTargetUriConfigBuilder uriTransformers(
         Collection<? extends IdentityPropagatorURITransformerConfig> uriTransformers
      ) {
         if (uriTransformers == null) {
            throw new NullPointerException("uriTransformers cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public ExternalTargetUriConfig.ExternalTargetUriConfigBuilder clearUriTransformers() {
         if (this.uriTransformers != null) {
            this.uriTransformers.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public ExternalTargetUriConfig build() {
         return new ExternalTargetUriConfig(this.targetUri, switch (this.uriTransformers == null ? 0 : this.uriTransformers.size()) {
            case 0 -> Collections.emptyList();
            case 1 -> Collections.singletonList(this.uriTransformers.get(0));
            default -> Collections.unmodifiableList(new ArrayList<>(this.uriTransformers));
         });
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "ExternalTargetUriConfig.ExternalTargetUriConfigBuilder(targetUri=" + this.targetUri + ", uriTransformers=" + this.uriTransformers + ")";
      }
   }
}
