package com.airlock.iam.login.app.misc.displaylanguage;

import com.airlock.iam.common.application.configuration.language.LanguageSettings;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

public final class DisplayLanguage implements Serializable {
   private static final ELogger LOG = ELoggerFactory.getLogger(DisplayLanguage.class);
   private final String language;
   private final DisplayLanguageSourceType sourceType;

   public DisplayLanguage(String language, DisplayLanguageSourceType sourceType) {
      Objects.requireNonNull(language, "language must not be null");
      Validate.notEmpty(language, "language must not be empty", new Object[0]);
      Objects.requireNonNull(sourceType, "sourceType must not be null");
      this.language = language;
      this.sourceType = sourceType;
   }

   public String getLanguage() {
      return this.language;
   }

   public DisplayLanguageSourceType getSourceType() {
      return this.sourceType;
   }

   public static DisplayLanguage determine(LanguageSettings languageSettings, DisplayLanguageExtractor... extractors) {
      DisplayLanguage result = new DisplayLanguage(languageSettings.getDefaultLanguage(), DisplayLanguageSourceType.DEFAULT_LANGUAGE);
      Set<DisplayLanguage> displayLanguages = new HashSet<>();
      if (extractors != null) {
         for (DisplayLanguageExtractor extractor : extractors) {
            Optional<DisplayLanguage> displayLanguage = extractor.extract(languageSettings);
            if (displayLanguage.isPresent()) {
               displayLanguages.add(displayLanguage.get());
            }
         }
      }

      for (DisplayLanguage displayLanguage : displayLanguages) {
         if (displayLanguage.getSourceType().getPriority() >= result.getSourceType().getPriority()) {
            if (languageSettings.isLanguageValid(displayLanguage.getLanguage())) {
               result = displayLanguage;
            } else {
               logInvalidLanguage(displayLanguage, languageSettings);
            }
         }
      }

      return result;
   }

   private static void logInvalidLanguage(DisplayLanguage invalidLanguage, LanguageSettings languageSettings) {
      LOG.debug("Ignoring " + invalidLanguage.toString() + " because it is not in the list of valid languages: " + languageSettings.getValidLanguages());
   }

   @Override
   public String toString() {
      return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
         .append("language", this.language)
         .append("priority", this.sourceType.getPriority())
         .append("source", this.sourceType.name())
         .toString();
   }
}
