package com.airlock.iam.saml2.infrastructure.plugin.configuration;

import com.airlock.iam.openfedlib.saml2.configuration.RefreshableConfigurationInstance;
import com.sun.identity.plugin.configuration.ConfigurationException;
import com.sun.identity.plugin.configuration.ConfigurationListener;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public final class ConfigurationInstanceImpl implements RefreshableConfigurationInstance {
   private InitializableConfiguration configuration;

   @Override
   public void init(String initComponentName, Object session) {
      Objects.requireNonNull(initComponentName, "Component name must not be null");
      this.configuration = ConfigurationInstanceImpl.KnownConfigurations.getConfigurationByComponentName(initComponentName);
   }

   @Override
   public void refreshConfig() throws ConfigurationException {
      this.configuration.refreshConfig();
   }

   @Override
   public Set<String> getAllConfigurationNames(String realm) throws ConfigurationException {
      this.checkInit();
      Set<String> configKeys = this.configuration.getConfigMap().keySet();
      return configKeys.isEmpty() ? null : configKeys;
   }

   @Override
   public Map<String, Set<String>> getConfiguration(@Nullable String realm, @Nullable String configName) throws ConfigurationException {
      this.checkInit();
      Map<String, Object> configMap = this.configuration.getConfigMap();
      if (configName == null) {
         return configMap.entrySet().stream().filter(e -> e.getValue() instanceof Set).collect(Collectors.toMap(Entry::getKey, e -> (Set<String>)e.getValue()));
      } else {
         return configMap.get(configName) instanceof Map ? (Map)configMap.get(configName) : Collections.emptyMap();
      }
   }

   @Override
   public String addListener(ConfigurationListener listener) {
      return this.configuration.addListener(listener);
   }

   private void checkInit() throws ConfigurationException {
      if (!this.configuration.isInitialized()) {
         this.configuration.initialize();
      }
   }

   private enum KnownConfigurations {
      SAML2(new FlowSaml2Configuration()),
      LIBCOT(new FlowCircleOfTrustConfiguration()),
      PLATFORM(new FlowPlatformConfiguration());

      private final InitializableConfiguration configuration;

      KnownConfigurations(InitializableConfiguration configuration) {
         this.configuration = configuration;
      }

      public static InitializableConfiguration getConfigurationByComponentName(String componentName) {
         return Stream.of(values())
            .map(ConfigurationInstanceImpl.KnownConfigurations::getConfiguration)
            .filter(c -> c.getComponentName().equals(componentName))
            .findAny()
            .orElse(new GenericConfiguration(componentName));
      }

      @SuppressFBWarnings(justification = "generated code")
      public InitializableConfiguration getConfiguration() {
         return this.configuration;
      }
   }
}
