package com.airlock.iam.ssi.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.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.types.api.application.configuration.step.StepConfigForAuthenticationFlows;
import com.airlock.iam.flow.types.api.application.configuration.step.StepConfigForSelfServiceFlows;
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.ssi.application.configuration.SsiAttributeMapping;
import com.airlock.iam.ssi.application.configuration.SsiServiceConfig;
import com.airlock.iam.ssi.application.configuration.VerifiableCredentialsRepositoryConfig;
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 = "SSI issuance step that persists the issued Verifiable Credential.\nInstructs the SSI service to issue a verifiable credential based on string values obtained\nfrom the specified value map providers.<p><b>This feature is incubating. Please consult the documentation for more information.</b></p>",
   displayName = "SSI Issuance Step"
)
public class SsiPersistedIssuanceStepConfig extends AbstractSsiIssuanceStepConfig implements StepConfigForAuthenticationFlows, StepConfigForSelfServiceFlows {
   @PluginProperty(
      displayName = "VC Repository",
      description = "The repository, which is used to persist verifiable credentials issued by this step. Along with this repository, an 'SSI User Change Listener' should also be configured in the relevant user persister.",
      optional = false
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private VerifiableCredentialsRepositoryConfig vcRepositoryConfig;

   public SsiPersistedIssuanceStepConfig(
      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,
      SsiServiceConfig service,
      String credentialSchemaName,
      List<ValueMapProviderConfig> valueProviders,
      List<SsiAttributeMapping> attributeMappings,
      VerifiableCredentialsRepositoryConfig vcRepositoryConfig
   ) {
      super(
         skipCondition,
         preCondition,
         requiresActivation,
         tagsOnSuccess,
         stepId,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes,
         service,
         credentialSchemaName,
         valueProviders,
         attributeMappings
      );
      this.vcRepositoryConfig = vcRepositoryConfig;
   }

   public VerifiableCredentialsRepositoryConfig getVcRepositoryConfig() {
      return this.vcRepositoryConfig;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class SsiPersistedIssuanceStepConfigBuilder {
      @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 List<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 SsiServiceConfig service;
      @SuppressFBWarnings(justification = "generated code")
      private String credentialSchemaName;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<ValueMapProviderConfig> valueProviders;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<SsiAttributeMapping> attributeMappings;
      @SuppressFBWarnings(justification = "generated code")
      private VerifiableCredentialsRepositoryConfig vcRepositoryConfig;

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder tagsOnSuccess(List<TagConfig> tagsOnSuccess) {
         this.tagsOnSuccess = tagsOnSuccess;
         return this;
      }

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

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

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

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

         return this;
      }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder 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 SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder clearDynamicStepActivations() {
         if (this.dynamicStepActivations != null) {
            this.dynamicStepActivations.clear();
         }

         return this;
      }

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder service(SsiServiceConfig service) {
         this.service = service;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder credentialSchemaName(String credentialSchemaName) {
         this.credentialSchemaName = credentialSchemaName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder valueProvider(ValueMapProviderConfig valueProvider) {
         if (this.valueProviders == null) {
            this.valueProviders = new ArrayList<>();
         }

         this.valueProviders.add(valueProvider);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder valueProviders(Collection<? extends ValueMapProviderConfig> valueProviders) {
         if (valueProviders == null) {
            throw new NullPointerException("valueProviders cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder clearValueProviders() {
         if (this.valueProviders != null) {
            this.valueProviders.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder attributeMapping(SsiAttributeMapping attributeMapping) {
         if (this.attributeMappings == null) {
            this.attributeMappings = new ArrayList<>();
         }

         this.attributeMappings.add(attributeMapping);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder attributeMappings(Collection<? extends SsiAttributeMapping> attributeMappings) {
         if (attributeMappings == null) {
            throw new NullPointerException("attributeMappings cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder clearAttributeMappings() {
         if (this.attributeMappings != null) {
            this.attributeMappings.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder vcRepositoryConfig(VerifiableCredentialsRepositoryConfig vcRepositoryConfig) {
         this.vcRepositoryConfig = vcRepositoryConfig;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiPersistedIssuanceStepConfig build() {
         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));
         };

         List dynamicStepActivations = 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));
         };

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

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

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "SsiPersistedIssuanceStepConfig.SsiPersistedIssuanceStepConfigBuilder(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
            + ", service="
            + this.service
            + ", credentialSchemaName="
            + this.credentialSchemaName
            + ", valueProviders="
            + this.valueProviders
            + ", attributeMappings="
            + this.attributeMappings
            + ", vcRepositoryConfig="
            + this.vcRepositoryConfig
            + ")";
      }
   }
}
