package com.airlock.iam.flow.shared.application.configuration.item;

import com.airlock.iam.common.api.application.configuration.validation.StringValidatorConfig;
import com.airlock.iam.core.application.configuration.contextdata.StringContextDataItemNameConfig;
import com.airlock.iam.flow.shared.api.application.configuration.ChannelVerifiableTargetDefinitionConfig;
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.PluginListProperty;
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;
import java.util.Optional;

@Plugin(
   description = "User context data item that stores a string value. This plugin must not be used for aliases.",
   displayName = "String User Context Data Item"
)
public final class StringContextDataItemDefinitionConfig implements ContextDataItemDefinitionConfig<String>, ChannelVerifiableTargetDefinitionConfig {
   @PluginProperty(description = "The context data item in the context data.", optional = false)
   private StringContextDataItemNameConfig contextDataName;
   @StringProperty(
      description = "<p>The input purpose allows labeling data items using standardized values\n(see <a href=\"https://www.w3.org/TR/WCAG22/#input-purposes\" target=\"_blank\">https://www.w3.org/TR/WCAG22/#input-purposes</a>).</p>\n<p>It is rendered using the HTML attribute \"autocomplete\".\nBrowsers can use this to automatically fill input fields with data that was previously entered in other fields with the same purpose.</p><p>Note that the input purpose provided here will be used in the default Loginapp UI components and is available to\ncustom single-page applications via the REST endpoints <code>*/info/retrieve</code>.</p>\n<p>If the Loginapp UI is used with <em>configuration-based</em> 'Customized Step UIs', the input purpose has to be defined on the UI elements\n('Input UI Element', 'Drop-Down UI Element', 'Date UI Element').</p>",
      optional = true,
      suggestedValues = {
            "name",
            "honorific-prefix",
            "given-name",
            "additional-name",
            "family-name",
            "honorific-suffix",
            "nickname",
            "organization-title",
            "username",
            "new-password",
            "current-password",
            "organization",
            "street-address",
            "address-line1",
            "address-line2",
            "address-line3",
            "address-level4",
            "address-level3",
            "address-level2",
            "address-level1",
            "country",
            "country-name",
            "postal-code",
            "cc-name",
            "cc-given-name",
            "cc-additional-name",
            "cc-family-name",
            "cc-number",
            "cc-exp",
            "cc-exp-month",
            "cc-exp-year",
            "cc-csc",
            "cc-type",
            "transaction-currency",
            "transaction-amount",
            "language",
            "bday",
            "bday-day",
            "bday-month",
            "bday-year",
            "sex",
            "url",
            "photo",
            "tel",
            "tel-country-code",
            "tel-national",
            "tel-area-code",
            "tel-local",
            "tel-local-prefix",
            "tel-local-suffix",
            "tel-extension",
            "email",
            "impp"
      }
   )
   private String inputPurpose;
   @BooleanProperty(
      description = "Specifies whether this context data item is required for the step to validate successfully.",
      defaultValue = "true",
      optional = true
   )
   private boolean required;
   @PluginListProperty(description = "The validators for this context data item.", optional = true)
   private List<StringValidatorConfig> validators;

   @Override
   public String getContextDataItemName() {
      return this.contextDataName.getContextDataName();
   }

   @Override
   public Class<String> getType() {
      return String.class;
   }

   @Override
   public boolean isRequired() {
      return this.required;
   }

   @Override
   public List<StringValidatorConfig> getValidators() {
      return this.validators;
   }

   @Override
   public Optional<String> getInputPurpose() {
      return Optional.ofNullable(this.inputPurpose);
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public StringContextDataItemDefinitionConfig(
      StringContextDataItemNameConfig contextDataName, String inputPurpose, boolean required, List<StringValidatorConfig> validators
   ) {
      this.contextDataName = contextDataName;
      this.inputPurpose = inputPurpose;
      this.required = required;
      this.validators = validators;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class StringContextDataItemDefinitionConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private StringContextDataItemNameConfig contextDataName;
      @SuppressFBWarnings(justification = "generated code")
      private String inputPurpose;
      @SuppressFBWarnings(justification = "generated code")
      private boolean required;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<StringValidatorConfig> validators;

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

      @SuppressFBWarnings(justification = "generated code")
      public StringContextDataItemDefinitionConfig.StringContextDataItemDefinitionConfigBuilder contextDataName(StringContextDataItemNameConfig contextDataName) {
         this.contextDataName = contextDataName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public StringContextDataItemDefinitionConfig.StringContextDataItemDefinitionConfigBuilder inputPurpose(String inputPurpose) {
         this.inputPurpose = inputPurpose;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public StringContextDataItemDefinitionConfig.StringContextDataItemDefinitionConfigBuilder required(boolean required) {
         this.required = required;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public StringContextDataItemDefinitionConfig.StringContextDataItemDefinitionConfigBuilder validator(StringValidatorConfig validator) {
         if (this.validators == null) {
            this.validators = new ArrayList<>();
         }

         this.validators.add(validator);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public StringContextDataItemDefinitionConfig.StringContextDataItemDefinitionConfigBuilder validators(
         Collection<? extends StringValidatorConfig> validators
      ) {
         if (validators == null) {
            throw new NullPointerException("validators cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public StringContextDataItemDefinitionConfig.StringContextDataItemDefinitionConfigBuilder clearValidators() {
         if (this.validators != null) {
            this.validators.clear();
         }

         return this;
      }

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

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "StringContextDataItemDefinitionConfig.StringContextDataItemDefinitionConfigBuilder(contextDataName="
            + this.contextDataName
            + ", inputPurpose="
            + this.inputPurpose
            + ", required="
            + this.required
            + ", validators="
            + this.validators
            + ")";
      }
   }
}
