package com.airlock.iam.flow.application.configuration.validation;

import com.airlock.iam.base.misc.log.LogUtil;
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.PropertyConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.PluginListPropertyValueReader;
import com.airlock.iam.plugin.api.valuereader.PluginPropertyValueReader;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

public class FlowIdConfigValidator {
   private final PluginConfiguration pc;
   private final ConfigurationEnvironment env;
   private final ConfigurationContext context;
   private final String flowsPropertyName;
   private final Optional<String> defaultFlowPropertyName;
   private final String flowIdProperty;

   public FlowIdConfigValidator(
      PluginConfiguration pc,
      ConfigurationEnvironment env,
      ConfigurationContext context,
      String flowsPropertyName,
      String defaultFlowPropertyName,
      String flowIdProperty
   ) {
      this.pc = pc;
      this.env = env;
      this.context = context;
      this.flowsPropertyName = flowsPropertyName;
      this.defaultFlowPropertyName = Optional.of(defaultFlowPropertyName);
      this.flowIdProperty = flowIdProperty;
   }

   public FlowIdConfigValidator(
      PluginConfiguration pc, ConfigurationEnvironment env, ConfigurationContext context, String flowsPropertyName, String flowIdProperty
   ) {
      this.pc = pc;
      this.env = env;
      this.context = context;
      this.flowsPropertyName = flowsPropertyName;
      this.defaultFlowPropertyName = Optional.empty();
      this.flowIdProperty = flowIdProperty;
   }

   public void validateFlowIdsUniqueForUis() throws PropertyConfigurationException {
      this.validateFlowIdsUnique("UIs");
   }

   public void validateFlowIdsUniqueForFlows() throws PropertyConfigurationException {
      this.validateFlowIdsUnique("flows");
   }

   private void validateFlowIdsUnique(String flowIdUsedIn) throws PropertyConfigurationException {
      Set<String> seenFlowIds = new HashSet<>();
      List<PluginConfiguration> flowPluginConfigs = PluginListPropertyValueReader.effectivePluginListPropertyValue(
         this.pc, this.flowsPropertyName, this.env, this.context
      );
      if (this.defaultFlowPropertyName.isPresent()) {
         PluginConfiguration defaultFlow = PluginPropertyValueReader.effectivePluginPropertyValue(
            this.pc, this.defaultFlowPropertyName.get(), this.env, this.context
         );
         if (defaultFlow != null) {
            flowPluginConfigs.add(defaultFlow);
         }
      }

      for (PluginConfiguration flow : flowPluginConfigs) {
         Optional<String> flowId = FlowStepIdConfigValidators.extractFlowId(flow, this.flowIdProperty, this.env, this.context);
         if (flowId.isPresent() && !seenFlowIds.add(flowId.get())) {
            throw new PropertyConstraintViolationException(
               this.flowsPropertyName, this.pc, this.env, this.context, "Flow ID " + LogUtil.quote(flowId.get()) + " is used for multiple " + flowIdUsedIn
            );
         }
      }
   }
}
