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.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.types.api.application.configuration.step.StepConfigForAuthenticationFlows;
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.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.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.annotation.property.PluginProperty;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import com.airlock.iam.ssi.application.configuration.SsiClaimConfig;
import com.airlock.iam.ssi.application.configuration.SsiServiceConfig;
import com.airlock.iam.ssi.domain.model.step.SsiVerificationStep;
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 = "The SSI verification step stores all verified attributes in the flow session, from which they can be read using the 'SSI Verification Data Provider'.<p>The authentication step, passwordless authentication step, and verification step all use the same UI. If translations need to differentiate between them,\n use <a href='https://docs.airlock.com/iam/latest/index/1642782415579.html'>customization with the design kit</a>.</p><p><b>This feature is incubating. Please consult the documentation for more information.</b></p>",
   displayName = "SSI Verification Step"
)
@PluginLicenseRestriction(moduleAffiliation = "AirlockIAM")
@NextActions(SsiVerificationStep.SsiVerificationActions.class)
@Groups(openGroups = "Basic Settings", groupSequence = {"Basic Settings", "Tags/Guards", "Flow Control", "Advanced Settings"})
public final class SsiVerificationStepConfig
   extends AbstractInteractiveFlowStepConfig
   implements StepConfigForAuthenticationFlows,
   StepConfigForUserSelfRegFlows,
   StepConfigForPublicSelfServiceFlows,
   StepConfigForSelfServiceFlows {
   @PluginProperty(description = "The SSI service to be used by this step.", optional = false)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private SsiServiceConfig service;
   @StringProperty(
      description = "<p>Restricts credential to this proof schema name.</p>\n<p>This schema name must exist on the configured service. The proof schema defines which attributes are requested from the user, see\n<a href='https://docs.procivis.ch/core/proof-schema-management'>Procivis Documentation</a> for more information.</p>",
      displayName = "Proof Schema Name",
      exampleValues = "Airlock Customer",
      optional = false
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private String proofSchemaName;
   @PluginListProperty(
      description = "The list of claims to be requested from the holder. Each item in the list specifies the attributes and predicates to be obtained from a single verifiable credential.",
      optional = false,
      minElements = 1
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private List<SsiClaimConfig> claims;

   SsiVerificationStepConfig(
      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,
      List<SsiClaimConfig> claims,
      String proofSchemaName
   ) {
      super(
         skipCondition,
         preCondition,
         requiresActivation,
         tagsOnSuccess,
         stepId,
         interactiveGotoTargets,
         dynamicStepActivations,
         onFailureGotos,
         customResponseAttributes,
         customFailureResponseAttributes
      );
      this.service = service;
      this.claims = claims;
      this.proofSchemaName = proofSchemaName;
   }

   public SsiServiceConfig getService() {
      return this.service;
   }

   public String getProofSchemaName() {
      return this.proofSchemaName;
   }

   public List<SsiClaimConfig> getClaims() {
      return this.claims;
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class SsiVerificationStepConfigBuilder {
      @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 List<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 SsiServiceConfig service;
      @SuppressFBWarnings(justification = "generated code")
      private ArrayList<SsiClaimConfig> claims;
      @SuppressFBWarnings(justification = "generated code")
      private String proofSchemaName;

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

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public SsiVerificationStepConfig.SsiVerificationStepConfigBuilder interactiveGotoTargets(List<InteractiveGotoTargetConfig> interactiveGotoTargets) {
         this.interactiveGotoTargets = interactiveGotoTargets;
         return this;
      }

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

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

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

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

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

      @SuppressFBWarnings(justification = "generated code")
      public SsiVerificationStepConfig.SsiVerificationStepConfigBuilder claim(SsiClaimConfig claim) {
         if (this.claims == null) {
            this.claims = new ArrayList<>();
         }

         this.claims.add(claim);
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiVerificationStepConfig.SsiVerificationStepConfigBuilder claims(Collection<? extends SsiClaimConfig> claims) {
         if (claims == null) {
            throw new NullPointerException("claims cannot be null");
         }

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

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

      @SuppressFBWarnings(justification = "generated code")
      public SsiVerificationStepConfig.SsiVerificationStepConfigBuilder clearClaims() {
         if (this.claims != null) {
            this.claims.clear();
         }

         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiVerificationStepConfig.SsiVerificationStepConfigBuilder proofSchemaName(String proofSchemaName) {
         this.proofSchemaName = proofSchemaName;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public SsiVerificationStepConfig build() {
         return new SsiVerificationStepConfig(
            this.skipCondition,
            this.preCondition,
            this.requiresActivation,
            this.tagsOnSuccess,
            this.stepId,
            this.interactiveGotoTargets,
            this.dynamicStepActivations,
            this.onFailureGotos,
            this.customResponseAttributes,
            this.customFailureResponseAttributes,
            this.service,
            switch (this.claims == null ? 0 : this.claims.size()) {
               case 0 -> Collections.emptyList();
               case 1 -> Collections.singletonList(this.claims.get(0));
               default -> Collections.unmodifiableList(new ArrayList<>(this.claims));
            },
            this.proofSchemaName
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "SsiVerificationStepConfig.SsiVerificationStepConfigBuilder(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
            + ", claims="
            + this.claims
            + ", proofSchemaName="
            + this.proofSchemaName
            + ")";
      }
   }
}
