package com.airlock.iam.configeditor.shared.domain;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.framework.misc.AppId;
import com.google.common.base.Suppliers;
import com.google.common.collect.Sets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public enum IamModuleConfigRoot {
   GLOBAL("globalConfig", "Main Settings", "com.airlock.iam.core.misc.plugin.config.GlobalConfiguration"),
   LOGINAPP("loginapp", "Loginapp", "com.airlock.iam.login.app.misc.configuration.Loginapp"),
   ADMINAPP("adminapp", "Adminapp", "com.airlock.iam.admin.application.configuration.Adminapp"),
   TRANSACTION_APPROVAL("transaction-approval", "Transaction Approval", "com.airlock.iam.transactionapproval.application.configuration.TransactionApprovalApp"),
   API_POLICY_SERVICE("api-policy-service", "API Policy Service", "com.airlock.iam.apipolicyservice.application.configuration.ApiPolicyServiceAppConfig"),
   SERVER("servicecontainerapp", "Service Container", "com.airlock.iam.servicecontainer.app.application.configuration.Server");

   private final AppId pluginConfigIdentifier;
   private final String configEditorCaption;
   private final String pluginClassName;
   private final Supplier<Class<?>> pluginBaseClass;

   IamModuleConfigRoot(String pluginConfigIdentifier, String configEditorCaption, String className) {
      Objects.requireNonNull(pluginConfigIdentifier, "Config identifier null");
      this.pluginConfigIdentifier = AppId.appId(pluginConfigIdentifier);
      this.configEditorCaption = configEditorCaption;
      this.pluginClassName = className;
      this.pluginBaseClass = Suppliers.memoize(() -> loadRootPluginClass(className));
   }

   private static Class<?> loadRootPluginClass(String clazzName) {
      try {
         return Class.forName(clazzName);
      } catch (ClassNotFoundException e) {
         throw new FailureException("Could not load root plugin class [" + clazzName + "]: " + e.getMessage(), e);
      }
   }

   public static Collection<IamModuleConfigRoot> contextAwareConfigRoots() {
      return Set.of(LOGINAPP, TRANSACTION_APPROVAL, API_POLICY_SERVICE);
   }

   public static boolean isModuleRootType(PluginConfiguration pc) {
      return isModuleRootType(pc.getPluginClassName());
   }

   public static boolean isModuleRootType(String className) {
      return Arrays.stream(values()).anyMatch(root -> root.getPluginClassName().equals(className));
   }

   public String getPluginDisplayName() {
      return this.pluginConfigIdentifier.id();
   }

   public String getConfigEditorCaption() {
      return this.configEditorCaption;
   }

   public String getPluginClassName() {
      return this.pluginClassName;
   }

   public Class<?> getPluginClass() {
      return this.pluginBaseClass.get();
   }

   public static boolean isModuleTreeRoot(PluginConfiguration pc) {
      return getByDisplayName(pc.getPluginDisplayName()) != null;
   }

   public static IamModuleConfigRoot getByDisplayName(String displayName) {
      return Arrays.stream(values()).filter(root -> root.getPluginDisplayName().equals(displayName)).findFirst().orElse(null);
   }

   public static Set<String> getRootPluginDisplayNames() {
      return Arrays.stream(values()).map(IamModuleConfigRoot::getPluginDisplayName).collect(Collectors.toCollection(Sets::newLinkedHashSet));
   }
}
