package com.airlock.iam.admin.application.configuration.maintenancemessages;

import com.airlock.iam.core.misc.sysmessage.MaintenanceMessagePersister;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Groups;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.property.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.GroupProperty;
import com.airlock.iam.plugin.api.annotation.property.IntegerProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginListProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginProperty;
import com.airlock.iam.plugin.api.annotation.property.StringListProperty;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.Environment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.ConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.PluginListPropertyValueReader;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.collections4.ListUtils;

@Plugin(description = "Configuration of the maintenance messages facility.")
@Groups(groupSequence = {"Basic Settings", "Advanced Settings"}, openGroups = "Basic Settings")
public class MaintenanceMessageConfiguration {
   @BooleanProperty(description = "Set to false to disable the navigation item for the maintenance messages facility.", optional = true, defaultValue = "true")
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private boolean enableMenuItem;
   @IntegerProperty(
      description = "Maximum number of messages per page to display on the maintenance messages list page.",
      optional = true,
      defaultValue = 50,
      minValue = 1,
      maxValue = 1000,
      exampleValues = {10, 25, 50, 100}
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private int messagesPerPage;
   @PluginProperty(description = "The persister plugin used to load and store maintenance message (e.g. from/to a database or directory.", optional = false)
   @GroupProperty(groupIdentifier = "Basic Settings")
   private MaintenanceMessagePersister persister;
   @StringListProperty(
      description = "List of valid languages. System messages can be configured for each defined language.<br/>Use the ISO-2-letter language code.",
      exampleElements = {"de", "en", "fr", "it"},
      minElements = 1,
      optional = false
   )
   @GroupProperty(groupIdentifier = "Basic Settings")
   private List<String> languages;
   @PluginListProperty(
      description = "<p>Multiple locations on the login page can be defined for separate maintenance messages. <p>The here configured locations are selectable in the maintenance message editor in the Adminapp. ",
      optional = true,
      minElements = 1
   )
   @GroupProperty(groupIdentifier = "Advanced Settings")
   private List<MaintenanceMessageLocation> locations;
   public static final String LOCATIONS_FIELD = "locations";

   @ConfigurationValidator
   public static void validateThatLocationNamesAreUnique(
      PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment
   ) throws ConfigurationException {
      List<String> locationNames = new ArrayList<>();

      for (PluginConfiguration location : PluginListPropertyValueReader.effectivePluginListPropertyValue(config, "locations", env, context)) {
         locationNames.add(StringPropertyValueReader.effectiveStringConfigValue(location, "locationName", env, context));
      }

      List<String> uniqueLocations = locationNames.stream().distinct().collect(Collectors.toList());
      List<String> duplicates = ListUtils.subtract(locationNames, uniqueLocations);
      if (!duplicates.isEmpty()) {
         throw new PropertyConstraintViolationException("locations", config, env, context, getDuplicatesMessage(duplicates));
      }
   }

   private static String getDuplicatesMessage(List<String> duplicates) {
      String message = "The 'Location Name' of all locations have to be unique.";

      for (String duplicate : duplicates) {
         message = message + "</br>Duplicated name: " + duplicate;
      }

      return message;
   }

   public List<String> getLocationNames() {
      return this.getLocations().stream().map(MaintenanceMessageLocation::getLocationName).collect(Collectors.toList());
   }

   public List<MaintenanceMessageLocationData> getLocationsData() {
      List<MaintenanceMessageLocationData> locationData = new ArrayList<>();

      for (MaintenanceMessageLocation location : this.getLocations()) {
         locationData.add(new MaintenanceMessageLocationData(location.getLocationName()));
      }

      return locationData;
   }

   public boolean isEnableMenuItem() {
      return this.enableMenuItem;
   }

   public int getMessagesPerPage() {
      return this.messagesPerPage;
   }

   public MaintenanceMessagePersister getPersister() {
      return this.persister;
   }

   public List<String> getLanguages() {
      return this.languages;
   }

   public List<MaintenanceMessageLocation> getLocations() {
      return this.locations;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static MaintenanceMessageConfiguration.MaintenanceMessageConfigurationBuilder builder() {
      return new MaintenanceMessageConfiguration.MaintenanceMessageConfigurationBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public MaintenanceMessageConfiguration() {
   }

   @SuppressFBWarnings(justification = "generated code")
   public MaintenanceMessageConfiguration(
      boolean enableMenuItem, int messagesPerPage, MaintenanceMessagePersister persister, List<String> languages, List<MaintenanceMessageLocation> locations
   ) {
      this.enableMenuItem = enableMenuItem;
      this.messagesPerPage = messagesPerPage;
      this.persister = persister;
      this.languages = languages;
      this.locations = locations;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class MaintenanceMessageConfigurationBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private boolean enableMenuItem;
      @SuppressFBWarnings(justification = "generated code")
      private int messagesPerPage;
      @SuppressFBWarnings(justification = "generated code")
      private MaintenanceMessagePersister persister;
      @SuppressFBWarnings(justification = "generated code")
      private List<String> languages;
      @SuppressFBWarnings(justification = "generated code")
      private List<MaintenanceMessageLocation> locations;

      @SuppressFBWarnings(justification = "generated code")
      MaintenanceMessageConfigurationBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public MaintenanceMessageConfiguration.MaintenanceMessageConfigurationBuilder enableMenuItem(boolean enableMenuItem) {
         this.enableMenuItem = enableMenuItem;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MaintenanceMessageConfiguration.MaintenanceMessageConfigurationBuilder messagesPerPage(int messagesPerPage) {
         this.messagesPerPage = messagesPerPage;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MaintenanceMessageConfiguration.MaintenanceMessageConfigurationBuilder persister(MaintenanceMessagePersister persister) {
         this.persister = persister;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MaintenanceMessageConfiguration.MaintenanceMessageConfigurationBuilder languages(List<String> languages) {
         this.languages = languages;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MaintenanceMessageConfiguration.MaintenanceMessageConfigurationBuilder locations(List<MaintenanceMessageLocation> locations) {
         this.locations = locations;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public MaintenanceMessageConfiguration build() {
         return new MaintenanceMessageConfiguration(this.enableMenuItem, this.messagesPerPage, this.persister, this.languages, this.locations);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "MaintenanceMessageConfiguration.MaintenanceMessageConfigurationBuilder(enableMenuItem="
            + this.enableMenuItem
            + ", messagesPerPage="
            + this.messagesPerPage
            + ", persister="
            + this.persister
            + ", languages="
            + this.languages
            + ", locations="
            + this.locations
            + ")";
      }
   }
}
