
package de.ivu.elect.business.gebietsbaum.boundary;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.ivu.elect.business.gebietsbaum.control.GebietsartCreate;
import de.ivu.elect.business.gebietsbaum.control.GebietsartenInitialerImport;
import de.ivu.elect.business.gebietsbaum.entity.AbstractGebietsart;
import de.ivu.elect.business.gebietsbaum.entity.Gebietsart;
import de.ivu.elect.business.mandant.boundary.MandantDAO;
import de.ivu.elect.business.mandant.entity.AbstractMandant;
import de.ivu.elect.business.mandant.entity.Mandant;

@Stateless
public class GebietsartCreator {

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

  @Inject
  private transient GebietsartDAO gebietsartDao;

  @Inject
  private transient GebietsartCreate gebietsartCreate;

  @Inject
  private transient DefaultAnzulegendeGebietsartCreator defaultAnzulegendeGebietsartCreator;

  @Inject
  private transient MandantDAO mandantDAO;

  @Inject
  private transient GebietsartenInitialerImport gebietsartenInitialerImport;

  public GebietsartCreator() {
    super();
  }

  @Deprecated // nur für Tests verwenden!
  protected GebietsartCreator(DefaultAnzulegendeGebietsartCreator defaultAnzulegendeGebietsartCreator) {
    super();

    this.defaultAnzulegendeGebietsartCreator = defaultAnzulegendeGebietsartCreator;
  }

  @TransactionAttribute(TransactionAttributeType.SUPPORTS)
  public Collection<? extends GebietsartTemplate> getGebietsartTemplates(Mandant mandant) {
    return getAllGebietsarten(mandant);
  }

  public Collection<? extends GebietsartTemplate> getAnzulegendeGebietsartTemplates() {
    Collection<GebietsartTemplate> result = new ArrayList<>(getAnzulegendeCustomGebietsartTemplates());

    // ELECT-7624
    for (GebietsartTemplate defaultGebietsartTemplate : getAnzulegendeDefaultGebietsartTemplates()) {
      if (result.stream().noneMatch(equalsCustomGebietsart(defaultGebietsartTemplate))) {
        result.add(defaultGebietsartTemplate);
      }
    }

    return result;
  }

  private Predicate<? super GebietsartTemplate> equalsCustomGebietsart(GebietsartTemplate defaultGebietsartTemplate) {
    return customGebietsartTemplate -> {
      boolean equalsCustomGebietsartName = customGebietsartTemplate.equalsGebietsart(defaultGebietsartTemplate.getGebietsartName());
      boolean equalsCustomGebietsartBezirksart = !defaultGebietsartTemplate.getGebietsartBezirksart().isKeine()
              && customGebietsartTemplate.getGebietsartBezirksart().equals(defaultGebietsartTemplate.getGebietsartBezirksart());

      return equalsCustomGebietsartName || equalsCustomGebietsartBezirksart;
    };
  }

  protected Collection<? extends GebietsartTemplate> getAnzulegendeDefaultGebietsartTemplates() {
    return defaultAnzulegendeGebietsartCreator.getAnzulegendeGebietsartTemplates();
  }

  protected Collection<? extends GebietsartTemplate> getAnzulegendeCustomGebietsartTemplates() {
    return defaultAnzulegendeGebietsartCreator.getAnzulegendeGebietsartTemplates();
  }

  public void initGebietsartenAlleMandanten() {
    for (Mandant mandant : mandantDAO.findByAll()) {
      if (mandant.getArt().isCustomerMandant()) {
        initGebietsarten(mandant);
      }
    }
  }

  public void initGebietsarten(Mandant mandant) {
    if (mandant.getArt().isCustomerMandant()) {
      LOG.info("Initialisiere Gebietsarten für Mandant: " + mandant.getNummer());
      if (mandant.getArt().isCustomerMandant()) {
        List<Gebietsart> vorhandeneGebietsarten = getAllGebietsarten(mandant);
        LOG.info("Vorhandene Gebietsarten: " + vorhandeneGebietsarten.size());
        boolean anglegt = false;

        for (GebietsartTemplate gebietsartTemplate : getAnzulegendeGebietsartTemplates()) {
          Gebietsart vorhandeneGebietsart = vorhanden(gebietsartTemplate, vorhandeneGebietsarten);
          if (vorhandeneGebietsart==null) {
            legeGebietsartAn(mandant, gebietsartTemplate);
            anglegt = true;
          } else {
            aktualisiereGebietsart(vorhandeneGebietsart, gebietsartTemplate);
          }
        }

        if (anglegt){
          gebietsartDao.flush();
        }
        gebietsartenInitialerImport.importiereGebietsartenWennVorhanden(mandant);
      } else {
        LOG.info("Gebietsarten für Mandant: " + mandant.getNummer() + " mit Art: " + mandant.getArt() + " werden nicht angelegt");
      }
    }
  }

  private void aktualisiereGebietsart(Gebietsart vorhandeneGebietsart, GebietsartTemplate gebietsartTemplate) {
    // ELECT-8350
    AbstractGebietsart.fillGebietsartFromTemplate(vorhandeneGebietsart, gebietsartTemplate);
    if (vorhandeneGebietsart.isAttributeChanged()) {
      LOG.info("Bestehende Gebietsart aktualisiert: " + vorhandeneGebietsart);
    } else {
      LOG.info("Bestehende Gebietsart unverändert: " + vorhandeneGebietsart);
    }
  }

  protected List<Gebietsart> getAllGebietsarten(Mandant mandant) {
    if (mandant.isPersistent()) {
      return gebietsartDao.findByAll(mandant);
    }

    // ELECTKOM-142
    LOG.error("ENTFERNEN ELECTKOM-142");
    return gebietsartDao.findByAll(AbstractMandant.getCustomerMandant(mandantDAO));
  }

  protected Gebietsart vorhanden(GebietsartTemplate gebietsartTemplate, List<Gebietsart> vorhandeneGebietsarten) {
    return vorhandeneGebietsarten.stream().filter(gebietsartTemplate::equalsGebietsart).findFirst().orElse(null);
  }

  public Gebietsart getGebietsart(Mandant mandant, GebietsartTemplate gebietsartTemplate) {
    for (Gebietsart gebietsart : getAllGebietsarten(mandant)) {
      if (gebietsartTemplate.equalsGebietsart(gebietsart)) {
        return gebietsart;
      }
    }

    throw new IllegalStateException("Keine Gebietsart gefunden: '" + gebietsartTemplate + "'");
  }

  protected void legeGebietsartAn(Mandant mandant, GebietsartTemplate gebietsartTemplate) {
    Gebietsart gebietsart = Gebietsart.createGebietsartFromTemplate(gebietsartTemplate);

    if (mandant.isPersistent()) {
      gebietsart.setMandant(mandant);
    } else {
      LOG.error("entfernen!! ELECTKOM-142");
      gebietsart.setMandant(AbstractMandant.getCustomerMandant(mandantDAO));
    }
    gebietsartCreate.save(gebietsart);

    LOG.info("Gebietsart '" + gebietsart.getName() + "' angelegt");
  }

  public GebietsartTemplate findByName(Mandant mandant, String gebietsartName) {
    Collection<? extends GebietsartTemplate> vorhandeneTemplates = getGebietsartTemplates(mandant);
    for (GebietsartTemplate gebietsartTemplate : vorhandeneTemplates) {
      if (gebietsartTemplate.equalsGebietsart(gebietsartName)) {
        return gebietsartTemplate;
      }
    }

    throw new IllegalArgumentException("Kein Gebietsart-Template mit dem Namen '" + gebietsartName + "' gefunden. Vorhandene Templates: " + vorhandeneTemplates);
  }
}
