package com.airlock.iam.publicselfservice.application.configuration.ui;

import com.airlock.iam.flow.api.application.configuration.step.FlowStepConfig;
import com.airlock.iam.flow.application.configuration.validation.FlowStepPluginConfiguration;
import com.airlock.iam.flow.ui.application.configuration.FlowStepUiConfigValidator;
import com.airlock.iam.flow.ui.application.configuration.StepUiPluginConfiguration;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.ConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.exception.PropertyTypeMismatchException;
import com.airlock.iam.plugin.api.valuereader.PluginListPropertyValueReader;
import com.airlock.iam.plugin.api.valuereader.StringListPropertyValueReader;
import com.airlock.iam.publicselfservice.application.configuration.steps.Airlock2FAPublicSelfServiceApprovalStepConfig;
import com.airlock.iam.publicselfservice.infrastructure.service.ui.PublicSelfServiceUiRepository;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public final class PublicSelfServiceUiConfigValidator extends FlowStepUiConfigValidator {
   private final PluginConfiguration publicSelfServiceUiConfig;
   private final PluginConfiguration flowConfig;

   public PublicSelfServiceUiConfigValidator(
      PluginConfiguration publicSelfServiceUiConfig, PluginConfiguration flowConfig, ConfigurationEnvironment environment, ConfigurationContext context
   ) {
      super(environment, context);
      this.publicSelfServiceUiConfig = publicSelfServiceUiConfig;
      this.flowConfig = flowConfig;
   }

   public void validate() throws ConfigurationException {
      List<FlowStepPluginConfiguration> stepConfigs = this.findAllFlowSteps(this.flowConfig);
      List<StepUiPluginConfiguration> stepUiConfigs = this.getAllStepUiConfigs();
      if (stepUiConfigs.isEmpty()) {
         this.verifyOnlyProductSteps(stepConfigs);
      } else {
         this.verifyUsingFlowStepsFromReferencedFlow(stepUiConfigs, stepConfigs);
         this.verifyReferencedStepsHaveValidType(stepUiConfigs, stepConfigs);
      }

      this.verifyInteractiveStepsWithGotoTargetsHaveStepIdWhenShowGotoButtons(this.publicSelfServiceUiConfig, stepConfigs);
      this.verifyAirlock2FAFactorStepHasMobileOnlyFalse(stepConfigs);
   }

   protected List<StepUiPluginConfiguration> getAllStepUiConfigs() throws PropertyTypeMismatchException {
      return PluginListPropertyValueReader.effectivePluginListPropertyValue(
            this.publicSelfServiceUiConfig, "customizedStepUis", this.getEnv(), this.getContext()
         )
         .stream()
         .map(plugin -> StepUiPluginConfiguration.wrapStepUiPluginConfiguration(plugin, this.customStepUiConfigTypes()))
         .collect(Collectors.toList());
   }

   private List<Class<?>> customStepUiConfigTypes() {
      return List.of(ConfigurablePublicSelfServiceStepUiConfig.class, CustomJavaScriptPublicSelfServiceStepUiConfig.class);
   }

   protected PropertyConstraintViolationException newStepUiConfigException(String message) {
      return new PropertyConstraintViolationException("customizedStepUis", this.publicSelfServiceUiConfig, this.getEnv(), this.getContext(), message);
   }

   protected Set<Class<? extends FlowStepConfig>> defaultUiCapableStepConfigTypes() {
      return PublicSelfServiceUiRepository.DEFAULT_UI_CAPABLE_PUBLIC_SELF_SERVICE_STEP_CONFIG_CLASSES;
   }

   private void verifyAirlock2FAFactorStepHasMobileOnlyFalse(List<FlowStepPluginConfiguration> flowStepConfigs) throws ConfigurationException {
      for (FlowStepPluginConfiguration flowStepConfig : flowStepConfigs) {
         if (this.isAirlock2FAFactorStepConfig(flowStepConfig) && this.mobileOnlyIsTrue(flowStepConfig)) {
            throw this.newStepUiConfigException(
               "The flow for this UI has a Airlock 2FA Factor Step with Mobile Only activated, which is for REST only. Please deactivate Mobile Only to be able to use it in the UI."
            );
         }
      }
   }

   private boolean isAirlock2FAFactorStepConfig(FlowStepPluginConfiguration flowStepConfig) {
      return flowStepConfig.isOfType(Airlock2FAPublicSelfServiceApprovalStepConfig.class);
   }

   private boolean mobileOnlyIsTrue(FlowStepPluginConfiguration flowStepConfig) throws PropertyTypeMismatchException {
      List<String> approvalFactors = StringListPropertyValueReader.effectiveStringListConfigValue(
         flowStepConfig.getPluginConfiguration(), "approvalFactors", this.getEnv(), this.getContext()
      );
      return approvalFactors.size() == 1 && approvalFactors.getFirst().equals("Mobile Only");
   }
}
