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

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

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

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

import de.ivu.elect.business.ElectSystemProperties;
import de.ivu.elect.business.konfiguration.control.SystemGebietsebeneAuswahl;
import de.ivu.elect.business.mandant.boundary.MandantDAO;
import de.ivu.elect.business.mandant.entity.AbstractMandant;
import de.ivu.elect.business.mandant.entity.Mandant;
import de.ivu.elect.business.mandant.entity.MandantArt;
import de.ivu.elect.business.mandant.entity.MandantStatus;
import de.ivu.elect.business.system.entity.SystemGebietsebene;
import de.ivu.elect.jee.faces.Messages;

@Stateless
public class MandantInit implements Serializable {

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

  private static final long serialVersionUID = 1L;

  @Inject
  private transient MandantDAO mandantDAO;

  @Inject
  private transient MandantCreate mandantCreate;

  @Inject
  private transient MandantSupport mandantSupport;

  @Inject
  private transient Messages messages;

  @Inject
  private transient SystemGebietsebeneAuswahl systemGebietsebeneAuswahl;

  @Inject
  private transient MandantenResourceLoader mandantenResourceLoader;

  /**
   * eigene Transaktion für Konfigurationsparameter nachfolgender Mandanten notwendig
   */
  public void initialisiereSystemMandant() {
    var mandants = mandantDAO.findByAll();
    LOG.info("Anzahl vorhandener Mandanten: " + mandants.size());

    if (mandants.isEmpty()) {
      LOG.info("Initialisiere System-Mandant - mehrere Mandanten unterstützt: " + mandantSupport.isMandantenUnterstuetzt());

      var systemMandant = new Mandant();
      systemMandant.setNummer(AbstractMandant.SYSTEM_MANDANT_NUMMER); // erster Mandant immer Systemmandant mit Nummer 0
      systemMandant.setStatus(MandantStatus.AKTIVIERT);

      if (mandantSupport.isMandantenUnterstuetzt()) {
        systemMandant.setArt(MandantArt.SYSTEM);
        systemMandant.setName("System");
        systemMandant.setBeschreibung("System");
        systemMandant.setSystemGebietsebene(SystemGebietsebene.OHNE);
      } else {
        systemMandant.setArt(MandantArt.OHNE_MANDANT);
        systemMandant.setName("Kein Mandant");
        systemMandant.setBeschreibung("Kein Mandant (Init)");
        systemMandant.setSystemGebietsebene(getDefaultSystemGebietsebene());
      }

      mandantCreate.save(systemMandant);
      LOG.info("Mandant angelegt: " + systemMandant.getArt() + ", Nummer: " + systemMandant.getNummer());

      LOG.info("Initialisiere System-Mandant - done");
    }
  }

  private SystemGebietsebene getDefaultSystemGebietsebene() {
    var property = System.getProperty(ElectSystemProperties.SYSTEM_GEBIETSEBENE);
    LOG.info("SystemGebietsebene-System-property: " + property);
    if (StringUtils.isNotBlank(property)) {
      try {
        return SystemGebietsebene.valueOf(property.toUpperCase());
      } catch (Exception e) {
        // ignorieren
        LOG.warn("Systemgebietsebene nicht erkannt: '" + property + "'");
      }
    }
    return getDefaultSystemGebietsebeneInternal();
  }

  protected SystemGebietsebene getDefaultSystemGebietsebeneInternal() {
    if (systemGebietsebeneAuswahl.getAvailableSystemGebietsebenen().size() == 1) {
      return systemGebietsebeneAuswahl.getAvailableSystemGebietsebenen().iterator().next();
    }

    return SystemGebietsebene.UNBEKANNT;
  }

  public void initialisiereKundenMandant() {
    var mandants = mandantDAO.findByAll();
    LOG.info("Anzahl vorhandener Mandanten: " + mandants.size());

    if (aktualisiereKundenMandantenAusResourceDatei(mandants)) {
      LOG.info("Kundenmandanten aus Resource-Datei aktualisiert");
    } else {
      if (mandants.size() == 1) {
        LOG.info("Initialisiere Kunden-Mandant - mehrere Mandanten unterstützt: " + mandantSupport.isMandantenUnterstuetzt());
        if (mandantSupport.isMandantenUnterstuetzt()) {
          for (var customerMandant : getAnzulegendeMandanten()) {
            saveMandant(customerMandant);
          }
        }
        LOG.info("Initialisiere Mandant - done");
      }
    }
  }

  private boolean aktualisiereKundenMandantenAusResourceDatei(List<Mandant> vorhandeneMandanten) {
    var mandantenResourceLines = mandantenResourceLoader.getMandantenResourceLines();
    if (mandantenResourceLines.isEmpty()) {
      return false;
    }

    var vorhandeneMandantenNachNummern = vorhandeneMandanten.stream()
        .collect(Collectors.toMap(Mandant::getNummer, mandant -> mandant, (a, b) -> b));
    for (var mandant : mandantenResourceLines.stream().map(this::toMandant).filter(Objects::nonNull)
        .sorted(Comparator.comparing(Mandant::getNummer)).collect(Collectors.toList())) {
      if (!vorhandeneMandantenNachNummern.containsKey(mandant.getNummer())) {
        saveMandant(mandant);
        vorhandeneMandantenNachNummern.put(mandant.getNummer(), mandant);
      }
    }
    return true;
  }

  private void saveMandant(Mandant mandant) {
    mandantCreate.save(mandant);
    LOG.info("Mandant angelegt: " + mandant.getArt() + ", Nummer: " + mandant.getNummer() + ", Name: " + mandant.getName());
  }

  @Nullable
  private Mandant toMandant(String row) {

    if (StringUtils.isBlank(row) || row.startsWith("#")) {
      return null;
    }

    var split = row.split(";");
    if (split.length > 1) {
      var verantworteteGebiete = "";
      if (split.length > 2) {
        verantworteteGebiete = split[2];
      }
      var systemGebietsebene = getDefaultSystemGebietsebene();
      if (split.length > 3) {
        systemGebietsebene = SystemGebietsebene.valueOf(split[3]);
      }
      var beschreibung = "";
      if (split.length > 4) {
        beschreibung = split[4];
      }

      return createCustomerMandant(Long.parseLong(split[0]), split[1], beschreibung, systemGebietsebene, verantworteteGebiete);
    }
    return null;
  }

  protected List<Mandant> getAnzulegendeMandanten() {
    List<Mandant> result = new ArrayList<>();

    result.add(createCustomerMandant(AbstractMandant.SYSTEM_MANDANT_NUMMER + 1L, messages.getMessageForMessageKey("mandant.beispiel.name"),
        messages.getMessageForMessageKey("mandant.beispiel.beschreibung"), getDefaultSystemGebietsebene(), null));
    return result;
  }

  protected Mandant createCustomerMandant(Long nummer, String name, @Nullable String beschreibung, SystemGebietsebene systemGebietsebene, @Nullable String verantworteteGebiete) {
    var customerMandant = new Mandant();
    customerMandant.setNummer(nummer); // zweiter Mandant Customer-Mandant mit Nummer 1
    customerMandant.setStatus(MandantStatus.AKTIVIERT);
    customerMandant.setArt(MandantArt.CUSTOMER);
    customerMandant.setName(name);
    customerMandant.setBeschreibung(beschreibung);
    customerMandant.setSystemGebietsebene(systemGebietsebene);
    customerMandant.setVerantworteteGebiete(verantworteteGebiete);
    return customerMandant;
  }

}
