package com.airlock.iam.plugin.framework.application.configuration;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
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.InitializeException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.exception.PropertyTypeMismatchException;
import com.airlock.iam.plugin.api.valuereader.BooleanPropertyValueReader;
import com.airlock.iam.plugin.api.valuereader.PluginListPropertyValueReader;
import com.airlock.iam.plugin.api.valuereader.PluginPropertyValueReader;
import com.airlock.iam.plugin.impl.PluginDisplayNameReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;

public abstract class PluginConfigurationWrapper<T> {
   private final PluginConfiguration pluginConfiguration;

   public Class<? extends T> getConfigType() throws ConfigurationException {
      try {
         return this.pluginConfiguration.getPluginClass();
      } catch (InitializeException e) {
         throw new ConfigurationException(
            this.pluginConfiguration,
            ConfigurationEnvironment.common(),
            ConfigurationContext.defaultContext(),
            String.format("Failed to load class %s", this.pluginConfiguration.getPluginClassName())
         );
      }
   }

   public boolean isOfType(Class<? extends T> expectedType) {
      return this.pluginConfiguration.getPluginClassName().equals(expectedType.getName());
   }

   public boolean isSubtypeOf(Class<? extends T> expectedType) {
      try {
         return expectedType.isAssignableFrom(this.getConfigType());
      } catch (ConfigurationException e) {
         return false;
      }
   }

   public Optional<PluginConfiguration> getEffectivePluginPropertyValue(String propertyName, ConfigurationEnvironment environment, ConfigurationContext context) throws PropertyTypeMismatchException {
      return Optional.ofNullable(PluginPropertyValueReader.effectivePluginPropertyValue(this.pluginConfiguration, propertyName, environment, context));
   }

   public List<PluginConfiguration> getEffectivePluginListPropertyValue(String propertyName, ConfigurationEnvironment environment, ConfigurationContext context) throws PropertyTypeMismatchException {
      return PluginListPropertyValueReader.effectivePluginListPropertyValue(this.pluginConfiguration, propertyName, environment, context);
   }

   public Boolean getEffectiveBooleanProperty(String propertyName, ConfigurationEnvironment environment, ConfigurationContext context) {
      try {
         return BooleanPropertyValueReader.effectiveBooleanPropertyValue(this.pluginConfiguration, propertyName, environment, context);
      } catch (PropertyTypeMismatchException | PropertyConstraintViolationException e) {
         throw new FailureException(e.getMessage());
      }
   }

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

   public Optional<String> getDisplayName() {
      return Optional.ofNullable(StringUtils.trimToNull(this.pluginConfiguration.getPluginDisplayName()));
   }

   @Deprecated(since = "8.5")
   public Optional<String> getIdentifier() {
      return this.getDisplayName();
   }

   public Optional<String> getPluginDisplayName() {
      try {
         return Optional.of(PluginDisplayNameReader.readDisplayName(this.pluginConfiguration.getPluginClass()));
      } catch (InitializeException e) {
         return Optional.empty();
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   protected PluginConfigurationWrapper(PluginConfiguration pluginConfiguration) {
      this.pluginConfiguration = pluginConfiguration;
   }

   @SuppressFBWarnings(justification = "generated code")
   public PluginConfiguration getPluginConfiguration() {
      return this.pluginConfiguration;
   }
}
