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

import com.airlock.iam.common.api.application.configuration.valueprovider.StringValueProviderConfig;
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.domain.model.step.acknowledgemessage.AcknowledgeMessageStep;
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.StepConfigForPublicSelfServiceFlows;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForSelfServiceFlows;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForTransactionApprovalFlows;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForUserSelfRegFlows;
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.property.GroupProperty;
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 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 = "Configures a message ID or a message to be acknowledged by a client during a flow. <p>This can be used for example to inform users about a concrete event happening inside the flow, e.g., a successful mandatory password change, steps inside user self-registration, etc. This step can return a static message ID or a message that was generated by the server. At least one has to be configured. The message ID expects the client to display a corresponding message, while the server message is composed on the server and can therefore contain dynamic properties available in the IAM flow.</p><p>The message ID and the server message will both be provided as an additional attribute inside the flow response under the key <tt>messageId</tt> and <tt>serverMessage</tt> respectively.</p>",
   displayName = "Acknowledge Message Step"
)
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control"})
@NextActions(AcknowledgeMessageStep.AcknowledgeMessageStepActions.class)
public class AcknowledgeMessageStepConfig
   extends AbstractInteractiveFlowStepConfig
   implements StepConfigForAuthenticationFlows,
   StepConfigForAuthorizationFlows,
   StepConfigForSelfServiceFlows,
   StepConfigForUserSelfRegFlows,
   StepConfigForPublicSelfServiceFlows,
   StepConfigForTransactionApprovalFlows {
   public static final String ACKNOWLEDGE_MESSAGE_STEP_DISPLAY_NAME = "Acknowledge Message Step";
   @StringProperty(
      description = "ID of the corresponding message which a client is expected to display. If a Server Message is configured, this is optional, but could still be useful, e.g. for the client to determine the title or styling.",
      displayName = "Message ID",
      optional = true,
      mandatoryUnless = "serverMessage"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String messageId;
   private static final String MESSAGE_ID = "messageId";
   @PluginProperty(
      description = "The message composed on the server, which can be displayed directly. If a Message ID is configured, this is optional, but can still be used to determine the actual message to be displayed.",
      optional = true,
      mandatoryUnless = "messageId"
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private StringValueProviderConfig serverMessage;
   private static final String SERVER_MESSAGE = "serverMessage";

   protected AcknowledgeMessageStepConfig(
      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,
      String messageId,
      StringValueProviderConfig serverMessage
   ) {
      super(
         skipCondition,
         preCondition,
         requiresActivation,
         tagsOnSuccess,
         stepId,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes
      );
      this.messageId = messageId;
      this.serverMessage = serverMessage;
   }

   @Nullable
   public String getMessageId() {
      return this.messageId;
   }

   @Nullable
   public StringValueProviderConfig getServerMessage() {
      return this.serverMessage;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class AcknowledgeMessageStepConfigBuilder {
      @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 ArrayList<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 String messageId;
      @SuppressFBWarnings(justification = "generated code")
      private StringValueProviderConfig serverMessage;

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

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder 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 AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder clearTagsOnSuccess() {
         if (this.tagsOnSuccess != null) {
            this.tagsOnSuccess.clear();
         }

         return this;
      }

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder 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 AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder clearInteractiveGotoTargets() {
         if (this.interactiveGotoTargets != null) {
            this.interactiveGotoTargets.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder dynamicStepActivation(DynamicStepActivationConfig dynamicStepActivation) {
         if (this.dynamicStepActivations == null) {
            this.dynamicStepActivations = new ArrayList<>();
         }

         this.dynamicStepActivations.add(dynamicStepActivation);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder dynamicStepActivations(
         Collection<? extends DynamicStepActivationConfig> dynamicStepActivations
      ) {
         if (dynamicStepActivations == null) {
            throw new NullPointerException("dynamicStepActivations cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder clearDynamicStepActivations() {
         if (this.dynamicStepActivations != null) {
            this.dynamicStepActivations.clear();
         }

         return this;
      }

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder messageId(String messageId) {
         this.messageId = messageId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder serverMessage(StringValueProviderConfig serverMessage) {
         this.serverMessage = serverMessage;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public AcknowledgeMessageStepConfig 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 AcknowledgeMessageStepConfig(
            this.skipCondition,
            this.preCondition,
            this.requiresActivation,
            tagsOnSuccess,
            this.stepId,
            interactiveGotoTargets,
            switch (this.dynamicStepActivations == null ? 0 : this.dynamicStepActivations.size()) {
               case 0 -> Collections.emptyList();
               case 1 -> Collections.singletonList(this.dynamicStepActivations.get(0));
               default -> Collections.unmodifiableList(new ArrayList<>(this.dynamicStepActivations));
            },
            this.onFailureGotos,
            this.customResponseAttributes,
            this.customFailureResponseAttributes,
            this.messageId,
            this.serverMessage
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "AcknowledgeMessageStepConfig.AcknowledgeMessageStepConfigBuilder(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
            + ", messageId="
            + this.messageId
            + ", serverMessage="
            + this.serverMessage
            + ")";
      }
   }
}
