package de.ivu.elect.business.lokalisierung.control;

import java.io.Serializable;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.lokalisierung.entity.LokalisierungLocale;


import static java.util.Arrays.asList;

/**
 * Keine CDI-Komponente, um direkt aus dem ResourceBundle drauf zugreifen zu können
 */

public class LokalisierungStore implements Serializable {

  private static final Logger LOG = LoggerFactory.getLogger(LokalisierungStore.class);

  public static final int MAX_ANZAHL_PLATZHALTER = 10;

  public static final AtomicBoolean SCHLUESSEL_PER_REQUEST_SAMMELN_AKTIV = new AtomicBoolean(false);

  private static final long serialVersionUID = -1L;

  private static boolean debugMode = false;

  private static final Map<LokalisierungLocale, Map<String, String>> propertiesNachLocale = new EnumMap<>(LokalisierungLocale.class);

  private static final Set<String> MISSING_KEY_PREFIX_ALLOWLIST = new HashSet<>(asList("", "internet.praesentation"));

  public static Enumeration<String> getKeys() {
    LOG.error("LokalisierungStore.getKeys - FIX ME(!)", new RuntimeException()); // Sollte nicht im Log erscheinen...wenn ja, Implementierung dieser Methode überdenken...
    return Collections.enumeration(handleKeySet());
  }

  public static Set<String> handleKeySet() {
    return propertiesNachLocale.getOrDefault(LokalisierungLocale.getFuehrendesLocale(), Collections.emptyMap()).keySet();
  }

  public static boolean containsKey(String key) {
    boolean result = false;
    if (propertiesNachLocale.containsKey(LokalisierungLocale.getFuehrendesLocale())) {
      result = propertiesNachLocale.getOrDefault(LokalisierungLocale.getFuehrendesLocale(), Collections.emptyMap()).containsKey(key);
    }
    if (!result && !isInAllowList(key)) {
      LOG.error("Missing key(contains): '" + key + "'"); // TODO entfernen, erstmal lassen, um fehlende Keys zu finden
    }
    return result;
  }

  private static boolean isInAllowList(String key) {
    if (key==null || StringUtils.isBlank(key)){
      return false;
    }

    if (MISSING_KEY_PREFIX_ALLOWLIST.contains(key)){
      return true;
    }

    return MISSING_KEY_PREFIX_ALLOWLIST.stream().anyMatch(key::startsWith);
  }

  public static Map<LokalisierungLocale, Map<String, String>> getPropertiesNachLocale() {
    return propertiesNachLocale;
  }

  private static final ThreadLocal<LokalisierungSchluesselCollector> lokalisierungSchluesselCollectorThreadLocal = new ThreadLocal<>();

  @Nullable
  public static String getPropertyForKeyAndLocale(String key, LokalisierungLocale locale) {
    if (isSchluesselPerRequestSammelnAktiv()) {
      LokalisierungSchluesselCollector collector = getLokalisierungSchluesselCollector();
      if (collector != null) {
        collector.addSchluessel(key);
      }
    }
    Map<String, String> propertiesNachLocaleOrDefault = propertiesNachLocale.getOrDefault(locale, Collections.emptyMap());
    String result = propertiesNachLocaleOrDefault.get(key);
    if (result == null && propertiesNachLocaleOrDefault.containsKey(key)) {
      result = ""; // Unterschied zwischen leeren Keys und nicht vorhandenen
    }
    if (result == null) {
      if (key != null && key.isEmpty()){
        return "";
      }
      if (LokalisierungLocale.getFuehrendesLocale().equals(locale)) {
        LOG.error("Missing key: '" + key + "'" + ", " + locale); // TODO entfernen, erstmal lassen, um fehlende Keys zu finden
      }

      // ELECTVAPP-475
      LokalisierungLocale serverLokaliserungsLocale = LokalisierungLocale.byLocale(Locale.getDefault());
      if (!serverLokaliserungsLocale.equals(locale)) {
        result = getPropertyForKeyAndLocale(key, serverLokaliserungsLocale);
        if (result == null) {
          LokalisierungLocale fuehrendesLocale = LokalisierungLocale.getFuehrendesLocale();
          if (!fuehrendesLocale.equals(locale)) {
            result =  getPropertyForKeyAndLocale(key, fuehrendesLocale);
          }
        }
      }


    }

    if (debugMode) {
      result = generateDebugValue(key, result);
    }

    return result;
  }

  @Nullable
  private static String generateDebugValue(String key, @Nullable String result) {

    // Platzhalter an key anhängen, damit diese ersetzt werden...
    if (key == null || result == null) {
      return key;
    }

    String debugKey = "";
    if (result.contains("{")) {
      debugKey = IntStream.range(0, MAX_ANZAHL_PLATZHALTER).mapToObj(i -> "{" + i + "}").filter(result::contains).map(platzhalter -> " - " + platzhalter).collect(Collectors.joining("", key, ""));
    }
    return debugKey;
  }

  public static boolean isDebugMode() {
    return debugMode;
  }

  public static void setDebugMode(boolean debugMode) {
    LokalisierungStore.debugMode = debugMode;
  }

  public static void setLokalisierungSchluesselCollector(LokalisierungSchluesselCollector lokalisierungSchluesselCollector) {
    lokalisierungSchluesselCollectorThreadLocal.set(lokalisierungSchluesselCollector);
  }

  public static LokalisierungSchluesselCollector getLokalisierungSchluesselCollector() {
    return lokalisierungSchluesselCollectorThreadLocal.get();
  }

  public static void removeLokalisierungSchluesselCollector() {
    lokalisierungSchluesselCollectorThreadLocal.remove();
  }

  public static boolean isSchluesselPerRequestSammelnAktiv() {
    return SCHLUESSEL_PER_REQUEST_SAMMELN_AKTIV.get();
  }
}
