package com.airlock.iam.plugin.framework.misc.config;

import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.property.PluginConfigurationProperties;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import lombok.NonNull;

public class PluginConfigurationPropertiesView {
   @NonNull
   private final PluginConfiguration pluginConfiguration;
   @NonNull
   private final ConfigurationEnvironment environment;
   private boolean inheritFromParent;
   private boolean inheritFromCommonEnvironment;

   public PluginConfigurationPropertiesView inheritFromParent() {
      this.inheritFromParent = true;
      return this;
   }

   public PluginConfigurationPropertiesView inheritFromCommonEnvironment() {
      this.inheritFromCommonEnvironment = !this.environment.isCommonEnvironment();
      return this;
   }

   public PluginConfigurationProperties getProperties() {
      if (!this.inheritFromParent && !this.inheritFromCommonEnvironment) {
         return this.pluginConfiguration.getEnvironmentSpecificProperties(this.environment);
      }

      PluginConfigurationProperties properties = new PluginConfigurationProperties();
      if (this.inheritFromParent && this.pluginConfiguration.hasParentConfiguration()) {
         List<PluginConfiguration> reversedParentHierarchy = this.getReversedParentHierarchy();
         if (this.inheritFromCommonEnvironment) {
            this.overrideWithPropertiesFromParentHierarchy(properties, reversedParentHierarchy, ConfigurationEnvironment.common());
         }

         this.overrideWithPropertiesFromParentHierarchy(properties, reversedParentHierarchy, this.environment);
      } else {
         if (this.inheritFromCommonEnvironment) {
            properties.overwriteWith(this.pluginConfiguration.getEnvironmentSpecificProperties(ConfigurationEnvironment.common()));
         }

         properties.overwriteWith(this.pluginConfiguration.getEnvironmentSpecificProperties(this.environment));
      }

      return properties;
   }

   private void overrideWithPropertiesFromParentHierarchy(
      PluginConfigurationProperties properties, List<PluginConfiguration> reversedParentHierarchy, ConfigurationEnvironment env
   ) {
      for (PluginConfiguration configuration : reversedParentHierarchy) {
         properties.overwriteWith(configuration.getEnvironmentSpecificProperties(env));
      }
   }

   private List<PluginConfiguration> getReversedParentHierarchy() {
      List<PluginConfiguration> parentHierarchy = new LinkedList<>();
      parentHierarchy.add(this.pluginConfiguration);

      for (PluginConfiguration current = this.pluginConfiguration; current.hasParentConfiguration(); current = current.getParentConfiguration()) {
         parentHierarchy.add(current.getParentConfiguration());
      }

      Collections.reverse(parentHierarchy);
      return parentHierarchy;
   }

   @SuppressFBWarnings(justification = "generated code")
   public PluginConfigurationPropertiesView(@NonNull PluginConfiguration pluginConfiguration, @NonNull ConfigurationEnvironment environment) {
      if (pluginConfiguration == null) {
         throw new NullPointerException("pluginConfiguration is marked non-null but is null");
      }

      if (environment == null) {
         throw new NullPointerException("environment is marked non-null but is null");
      }

      this.pluginConfiguration = pluginConfiguration;
      this.environment = environment;
   }

   @SuppressFBWarnings(justification = "generated code")
   public boolean isInheritFromCommonEnvironment() {
      return this.inheritFromCommonEnvironment;
   }
}
