package com.airlock.iam.plugin.configeditor.data;

import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.exception.ConfigurationException;
import com.airlock.iam.plugin.api.exception.PluginClassLoadingException;
import com.airlock.iam.plugin.api.exception.PropertyConfigurationException;
import com.airlock.iam.plugin.framework.application.configuration.MutablePluginConfiguration;
import com.google.common.collect.Lists;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class ErrorBean {
   private final ConfigurationException exception;
   private final String pluginConfigurationName;
   private final String pluginConfigurationDisplayName;
   private final String configurationContextName;
   private final String description;
   private final String propertyName;

   public ErrorBean(ConfigurationException exception) {
      this.exception = exception;
      MutablePluginConfiguration pc = (MutablePluginConfiguration)exception.getPluginConfiguration();
      this.pluginConfigurationName = pc.getPluginClassDisplayName();
      this.pluginConfigurationDisplayName = pc.getPluginDisplayName();
      this.configurationContextName = exception.getConfigurationContext().toString();
      if (exception instanceof PropertyConfigurationException pce) {
         List<String> propertyDisplayNames = Lists.newArrayList();

         List<ConfigurableProperty> properties;
         try {
            properties = ConfigurablePropertyFactory.getInstance()
               .createProperties(pc, ConfigurationEnvironment.common(), ConfigurationContext.defaultContext());
         } catch (PluginClassLoadingException e) {
            this.description = e.getMessage();
            this.propertyName = "-";
            return;
         }

         for (String name : pce.getPropertyNames()) {
            propertyDisplayNames.add(this.getDisplayName(properties, name));
         }

         this.propertyName = StringUtils.join(propertyDisplayNames, ", ");
         this.description = pce.getDescription();
      } else {
         this.description = exception.getMessage();
         this.propertyName = "-";
      }
   }

   private String getDisplayName(List<ConfigurableProperty> properties, String name) {
      for (ConfigurableProperty p : properties) {
         if (p.getConfigPropertyName().equals(name)) {
            return p.getDisplayName();
         }
      }

      return name;
   }

   public String getPluginConfigurationName() {
      return this.pluginConfigurationName;
   }

   public String getPluginConfigurationDisplayName() {
      return this.pluginConfigurationDisplayName;
   }

   public String getConfigurationContextName() {
      return this.configurationContextName;
   }

   public String getPropertyName() {
      return this.propertyName;
   }

   public String getDescription() {
      return this.description;
   }

   public ConfigurationException getException() {
      return this.exception;
   }

   @Override
   public boolean equals(Object obj) {
      return obj instanceof ErrorBean other
         ? new EqualsBuilder()
            .append(this.exception.getClass(), other.exception.getClass())
            .append(this.pluginConfigurationName, other.pluginConfigurationName)
            .append(this.pluginConfigurationDisplayName, other.pluginConfigurationDisplayName)
            .append(this.configurationContextName, other.configurationContextName)
            .append(this.description, other.description)
            .append(this.propertyName, other.propertyName)
            .isEquals()
         : false;
   }

   @Override
   public int hashCode() {
      return new HashCodeBuilder()
         .append(this.exception.getClass())
         .append(this.pluginConfigurationName)
         .append(this.pluginConfigurationDisplayName)
         .append(this.configurationContextName)
         .append(this.description)
         .append(this.propertyName)
         .toHashCode();
   }
}
