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

import com.airlock.iam.flow.api.application.configuration.dynamicactivation.DynamicStepActivationConfig;
import com.airlock.iam.flow.api.application.configuration.selection.FlowConditionConfig;
import com.airlock.iam.flow.api.application.configuration.step.AbstractInteractiveFlowStepConfig;
import com.airlock.iam.flow.api.application.configuration.step.InteractiveGotoTargetConfig;
import com.airlock.iam.flow.api.application.configuration.step.StepIdConfig;
import com.airlock.iam.flow.api.application.configuration.tag.TagConfig;
import com.airlock.iam.flow.api.application.configuration.valueprovider.ValueMapProviderConfig;
import com.airlock.iam.flow.shared.api.application.configuration.item.SelfServiceItemDefinitionConfig;
import com.airlock.iam.flow.shared.application.configuration.validation.EditableItemNamesValidator;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForAuthenticationFlows;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForAuthorizationFlows;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForSelfServiceFlows;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Groups;
import com.airlock.iam.plugin.api.annotation.config.NextActions;
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.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginListProperty;
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.valuereader.PluginListPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

@Plugin(
   description = "<p>Flow step for editing user data.</p><p>Note that for the changes made in this step to take effect, an \"Apply Changes Step\" must be configured after it in the same flow. If not, the user data changes made in this step are lost.</p>",
   displayName = "User Data Edit Step"
)
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control"})
@PluginLicenseRestriction(moduleAffiliation = "UserProfileSelfService")
@NextActions(CommonDataEditStepConfig.DefaultNextDataEditActionCodes.class)
public final class UserDataEditStepConfig
   extends AbstractInteractiveFlowStepConfig
   implements CommonDataEditStepConfig,
   StepConfigForSelfServiceFlows,
   StepConfigForAuthenticationFlows,
   StepConfigForAuthorizationFlows {
   public static final String USER_DATA_EDIT_STEP_DISPLAY_NAME = "User Data Edit Step";
   @PluginListProperty(description = "Defines the items that can be edited in this step.", displayName = "Editable Items", optional = false, minElements = 1)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private List<SelfServiceItemDefinitionConfig> userDataItems;
   public static final String USER_DATA_ITEMS_PROPERTY_NAME = "userDataItems";

   @ConfigurationValidator
   public static void validateDataItems(
      PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      List<PluginConfiguration> itemConfigs = PluginListPropertyValueReader.effectivePluginListPropertyValue(config, "userDataItems", env, context);
      EditableItemNamesValidator validator = new EditableItemNamesValidator(config, "userDataItems", itemConfigs, context, env);
      validator.validateItemNames();
      validator.validateMaxOneMtanNumberAndLabel();
   }

   private UserDataEditStepConfig(
      FlowConditionConfig skipCondition,
      FlowConditionConfig preCondition,
      boolean requiresActivation,
      List<TagConfig> tagsOnSuccess,
      @Nullable StepIdConfig stepId,
      List<InteractiveGotoTargetConfig> interactiveGotoTargets,
      List<DynamicStepActivationConfig> dynamicStepActivations,
      Map<String, StepIdConfig> onFailureGotos,
      List<ValueMapProviderConfig> customResponseAttributes,
      List<ValueMapProviderConfig> customFailureResponseAttributes,
      List<SelfServiceItemDefinitionConfig> userDataItems
   ) {
      super(
         skipCondition,
         preCondition,
         requiresActivation,
         tagsOnSuccess,
         stepId,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes
      );
      this.userDataItems = userDataItems;
   }

   @Override
   public List<SelfServiceItemDefinitionConfig> getUserDataItems() {
      return this.userDataItems;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class UserDataEditStepConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private FlowConditionConfig skipCondition;
      @SuppressFBWarnings(justification = "generated code")
      private FlowConditionConfig preCondition;
      @SuppressFBWarnings(justification = "generated code")
      private boolean requiresActivation;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<TagConfig> tagsOnSuccess;
      @SuppressFBWarnings(justification = "generated code")
      private StepIdConfig stepId;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<InteractiveGotoTargetConfig> interactiveGotoTargets;
      @SuppressFBWarnings(justification = "generated code")
      private List<DynamicStepActivationConfig> dynamicStepActivations;
      @SuppressFBWarnings(justification = "generated code")
      private Map<String, StepIdConfig> onFailureGotos;
      @SuppressFBWarnings(justification = "generated code")
      private List<ValueMapProviderConfig> customResponseAttributes;
      @SuppressFBWarnings(justification = "generated code")
      private List<ValueMapProviderConfig> customFailureResponseAttributes;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<SelfServiceItemDefinitionConfig> userDataItems;

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

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder skipCondition(FlowConditionConfig skipCondition) {
         this.skipCondition = skipCondition;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder preCondition(FlowConditionConfig preCondition) {
         this.preCondition = preCondition;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder requiresActivation(boolean requiresActivation) {
         this.requiresActivation = requiresActivation;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder tagOnSuccess(TagConfig tagOnSuccess) {
         if (this.tagsOnSuccess == null) {
            this.tagsOnSuccess = new ArrayList<>();
         }

         this.tagsOnSuccess.add(tagOnSuccess);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder tagsOnSuccess(Collection<? extends TagConfig> tagsOnSuccess) {
         if (tagsOnSuccess == null) {
            throw new NullPointerException("tagsOnSuccess cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder clearTagsOnSuccess() {
         if (this.tagsOnSuccess != null) {
            this.tagsOnSuccess.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder stepId(@Nullable StepIdConfig stepId) {
         this.stepId = stepId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder interactiveGotoTarget(InteractiveGotoTargetConfig interactiveGotoTarget) {
         if (this.interactiveGotoTargets == null) {
            this.interactiveGotoTargets = new ArrayList<>();
         }

         this.interactiveGotoTargets.add(interactiveGotoTarget);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder interactiveGotoTargets(
         Collection<? extends InteractiveGotoTargetConfig> interactiveGotoTargets
      ) {
         if (interactiveGotoTargets == null) {
            throw new NullPointerException("interactiveGotoTargets cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder clearInteractiveGotoTargets() {
         if (this.interactiveGotoTargets != null) {
            this.interactiveGotoTargets.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder dynamicStepActivations(List<DynamicStepActivationConfig> dynamicStepActivations) {
         this.dynamicStepActivations = dynamicStepActivations;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder onFailureGotos(Map<String, StepIdConfig> onFailureGotos) {
         this.onFailureGotos = onFailureGotos;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder customResponseAttributes(List<ValueMapProviderConfig> customResponseAttributes) {
         this.customResponseAttributes = customResponseAttributes;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder customFailureResponseAttributes(List<ValueMapProviderConfig> customFailureResponseAttributes) {
         this.customFailureResponseAttributes = customFailureResponseAttributes;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder userDataItem(SelfServiceItemDefinitionConfig userDataItem) {
         if (this.userDataItems == null) {
            this.userDataItems = new ArrayList<>();
         }

         this.userDataItems.add(userDataItem);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder userDataItems(Collection<? extends SelfServiceItemDefinitionConfig> userDataItems) {
         if (userDataItems == null) {
            throw new NullPointerException("userDataItems cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public UserDataEditStepConfig.UserDataEditStepConfigBuilder clearUserDataItems() {
         if (this.userDataItems != null) {
            this.userDataItems.clear();
         }

         return this;
      }

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

         List interactiveGotoTargets = switch (this.interactiveGotoTargets == null ? 0 : this.interactiveGotoTargets.size()) {
            case 0 -> Collections.emptyList();
            case 1 -> Collections.singletonList(this.interactiveGotoTargets.get(0));
            default -> Collections.unmodifiableList(new ArrayList<>(this.interactiveGotoTargets));
         };

         return new UserDataEditStepConfig(
            this.skipCondition,
            this.preCondition,
            this.requiresActivation,
            tagsOnSuccess,
            this.stepId,
            interactiveGotoTargets,
            this.dynamicStepActivations,
            this.onFailureGotos,
            this.customResponseAttributes,
            this.customFailureResponseAttributes,
            switch (this.userDataItems == null ? 0 : this.userDataItems.size()) {
               case 0 -> Collections.emptyList();
               case 1 -> Collections.singletonList(this.userDataItems.get(0));
               default -> Collections.unmodifiableList(new ArrayList<>(this.userDataItems));
            }
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "UserDataEditStepConfig.UserDataEditStepConfigBuilder(skipCondition="
            + this.skipCondition
            + ", preCondition="
            + this.preCondition
            + ", requiresActivation="
            + this.requiresActivation
            + ", tagsOnSuccess="
            + this.tagsOnSuccess
            + ", stepId="
            + this.stepId
            + ", interactiveGotoTargets="
            + this.interactiveGotoTargets
            + ", dynamicStepActivations="
            + this.dynamicStepActivations
            + ", onFailureGotos="
            + this.onFailureGotos
            + ", customResponseAttributes="
            + this.customResponseAttributes
            + ", customFailureResponseAttributes="
            + this.customFailureResponseAttributes
            + ", userDataItems="
            + this.userDataItems
            + ")";
      }
   }
}
