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

import com.airlock.iam.flow.api.application.configuration.redflag.RedFlagConfig;
import com.airlock.iam.flow.api.application.configuration.selection.FlowConditionConfig;
import com.airlock.iam.flow.api.application.configuration.step.AbstractFlowStepConfig;
import com.airlock.iam.flow.api.application.configuration.step.NonInteractiveStepConfig;
import com.airlock.iam.flow.api.application.configuration.step.RedFlagHandlingStepConfig;
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.types.api.application.configuration.step.StepConfigForAuthenticationFlows;
import com.airlock.iam.oauth2.application.configuration.OAuth2ProviderIdentifierConfig;
import com.airlock.iam.plugin.api.annotation.config.Groups;
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.PluginProperty;
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;
import java.util.Optional;

@Plugin(
   description = "For the user identified within the current authentication flow, this step creates an account link to the provider account, which was also identified within the current authentication flow. This step will take down the corresponding \"red flag\" that has been raised by a previous step (e.g. OAuth 2.0 SSO Step). The step will be skipped, if the \"red flag\" was not raised by a previous step.",
   displayName = "Missing Account Link Step"
)
@PluginLicenseRestriction(moduleAffiliation = "OAuthAccountLinking")
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control", "Advanced Settings"})
public final class MissingAccountLinkStepConfig
   extends AbstractFlowStepConfig
   implements StepConfigForAuthenticationFlows,
   NonInteractiveStepConfig,
   RedFlagHandlingStepConfig {
   public static final String MISSING_ACCOUNT_LINK_STEP = "Missing Account Link Step";
   @GroupProperty(groupIdentifier = "Tags/Guards")
   @PluginProperty(
      description = "Handles ('takes down') this red flag concerning a missing account link, if it has been raised. The step will be skipped, if this red flag has not been raised by a previous step.",
      defaultValue = AccountLinkingRequiredRedFlagConfig.class,
      optional = true
   )
   private RedFlagConfig redFlag;
   private FlowConditionConfig skipCondition;
   private boolean requiresActivation;

   private MissingAccountLinkStepConfig(
      FlowConditionConfig skipCondition,
      FlowConditionConfig preCondition,
      boolean requiresActivation,
      List<TagConfig> tagsOnSuccess,
      @Nullable StepIdConfig stepId,
      Map<String, StepIdConfig> onFailureGotos,
      List<ValueMapProviderConfig> customResponseAttributes,
      List<ValueMapProviderConfig> customFailureResponseAttributes,
      OAuth2ProviderIdentifierConfig providerId,
      RedFlagConfig redFlag
   ) {
      super(skipCondition, preCondition, requiresActivation, tagsOnSuccess, stepId, onFailureGotos, customResponseAttributes, customFailureResponseAttributes);
      this.redFlag = redFlag;
   }

   @Override
   public Optional<FlowConditionConfig> getSkipCondition() {
      return Optional.empty();
   }

   @Override
   public RedFlagConfig getRedFlag() {
      return this.redFlag;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class MissingAccountLinkStepConfigBuilder {
      @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 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 OAuth2ProviderIdentifierConfig providerId;
      @SuppressFBWarnings(justification = "generated code")
      private RedFlagConfig redFlag;

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

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

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

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

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

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

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

         return this;
      }

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public MissingAccountLinkStepConfig.MissingAccountLinkStepConfigBuilder providerId(OAuth2ProviderIdentifierConfig providerId) {
         this.providerId = providerId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MissingAccountLinkStepConfig.MissingAccountLinkStepConfigBuilder redFlag(RedFlagConfig redFlag) {
         this.redFlag = redFlag;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MissingAccountLinkStepConfig build() {
         return new MissingAccountLinkStepConfig(
            this.skipCondition, this.preCondition, this.requiresActivation, 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));
            }, this.stepId, this.onFailureGotos, this.customResponseAttributes, this.customFailureResponseAttributes, this.providerId, this.redFlag
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "MissingAccountLinkStepConfig.MissingAccountLinkStepConfigBuilder(skipCondition="
            + this.skipCondition
            + ", preCondition="
            + this.preCondition
            + ", requiresActivation="
            + this.requiresActivation
            + ", tagsOnSuccess="
            + this.tagsOnSuccess
            + ", stepId="
            + this.stepId
            + ", onFailureGotos="
            + this.onFailureGotos
            + ", customResponseAttributes="
            + this.customResponseAttributes
            + ", customFailureResponseAttributes="
            + this.customFailureResponseAttributes
            + ", providerId="
            + this.providerId
            + ", redFlag="
            + this.redFlag
            + ")";
      }
   }
}
