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

import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.inject.Inject;

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

import de.ivu.elect.business.benutzerverwaltung.boundary.AbstractBenutzerEinsatzortDAO;
import de.ivu.elect.business.benutzerverwaltung.entity.BenutzerEinsatzort;
import de.ivu.elect.business.benutzerverwaltung.entity.BenutzerEinsatzortPK;
import de.ivu.elect.business.benutzerverwaltung.entity.BenutzereinsatzortAuswahl;
import de.ivu.elect.business.benutzerverwaltung.entity.Rolle;
import de.ivu.elect.business.konfiguration.entity.AbstractKonfigurationLoader;
import de.ivu.elect.business.konfiguration.entity.MandantKonfigurationWerte;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.system.boundary.SystemLogWriter;
import de.ivu.elect.jee.security.IpHostname;


import static de.ivu.elect.business.system.entity.SystemLogQuelle.SECURITY;
import static java.util.stream.Collectors.toList;

public abstract class AbstractBenutzerEinsatzortBestimmer implements Serializable {

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

  private static final long serialVersionUID = 1L;

  @Inject
  private transient SystemLogWriter systemLogWriter;

  @Nullable
  public BenutzerEinsatzortPK bestimmeBenutzerEinsatzort(Mandant mandant, IpHostname ipHostname) {
    if (bestimmeBenutzereinsatzortAuswahl(mandant).isPerIpAdresseFinden()) {
      String ip = ipHostname.getIp();
      if (StringUtils.isBlank(ip)) {
        LOG.warn("Keine IP-Adresse angegeben");
        return null;
      }
      List<BenutzerEinsatzort> benutzerEinsatzorte = getBenutzerEinsatzortDAO().findByAll(mandant)
          .stream().filter(be -> be.matches(ip))
          .collect(toList());

      if (benutzerEinsatzorte.isEmpty()) {
        LOG.info("Kein Benutzereinsatzort für IP-Adresse: '" + ip + "' gefunden");
        return null;
      }
      if (benutzerEinsatzorte.size() == 1) {
        BenutzerEinsatzort benutzerEinsatzort = benutzerEinsatzorte.get(0);
        LOG.info("Benutzereinsatzort für IP-Adresse: '" + ip + "' ist: " + mappeNamePattern(
            benutzerEinsatzort) + ", damit erhält der Benutzer folgende Rollen durch den Einsatzort: " + benutzerEinsatzort.getRolles().stream().map(
            Rolle::getName).sorted().collect(Collectors.joining(", ")));
        return benutzerEinsatzort.getPk();
      }

      systemLogWriter.writeErrorLogMessageFuerMandant(mandant,
          "FEHLKONFIGURATION: Mehr als ein Benutzereinsatzort für IP-Adresse: '" + ip + "' gefunden, mögliche Treffer: " + benutzerEinsatzorte.stream()
              .map(this::mappeNamePattern).collect(
                  Collectors.joining(", ")) + " - verwende KEINEN EINSATZORT(!)", SECURITY);
    }
    return null;

  }

  protected abstract AbstractBenutzerEinsatzortDAO getBenutzerEinsatzortDAO();

  private String mappeNamePattern(BenutzerEinsatzort benutzerEinsatzort) {
    return benutzerEinsatzort.getName() + " (" + benutzerEinsatzort.getClientIpMuster() + ")";
  }

  protected BenutzereinsatzortAuswahl bestimmeBenutzereinsatzortAuswahl(Mandant mandant) {
    BenutzereinsatzortAuswahl benutzereinsatzortAuswahl = getKonfigurationLoader().resolveEnumValue(mandant,
        MandantKonfigurationWerte.BENUTZEREINSATZORT_AUSWAHL, BenutzereinsatzortAuswahl.class);
    if (benutzereinsatzortAuswahl == null) {
      return BenutzereinsatzortAuswahl.OHNE;
    }
    return benutzereinsatzortAuswahl;
  }

  protected abstract AbstractKonfigurationLoader getKonfigurationLoader();

}
