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

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

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

import de.ivu.elect.business.benutzerverwaltung.control.RechteKonfigurationAktualisierenEvent;
import de.ivu.elect.business.benutzerverwaltung.control.RechteKonfigurationImportExchange;
import de.ivu.elect.business.benutzerverwaltung.entity.RechteKonfiguration;
import de.ivu.elect.business.benutzerverwaltung.entity.RechteKonfigurationExchangeContext;
import de.ivu.elect.business.benutzerverwaltung.entity.RechteKonfigurationMeta;
import de.ivu.elect.business.benutzerverwaltung.entity.RechteKonfigurationTK;
import de.ivu.elect.business.datei.entity.DateiImport;
import de.ivu.elect.business.datei.entity.DateiImportBerichtCustomData;
import de.ivu.elect.business.exchange.control.AbstractEntityImporter;
import de.ivu.elect.business.exchange.control.ImportExchange;
import de.ivu.elect.business.exchange.entity.ImportUpdateReport;
import de.ivu.elect.business.security.UseCasePermission;
import de.ivu.elect.business.security.boundary.RolleCreator;
import de.ivu.elect.jee.entity.Meta;
import de.ivu.elect.jee.exchange.ImportOptions;
import de.ivu.elect.jee.exchange.Violations;
import de.ivu.elect.util.CollectionSeparator;

/**
 * Unterstützung für verscheidene ImportOptions erst einmal wieder entfernt, weil sich die fachliche und technische
 * Sicht auf die Objekte stark unterscheidet.
 * <p>
 *  on 16.07.2015.
 */
@Stateless
public class RechteKonfigurationImporter
    extends
    AbstractEntityImporter<RechteKonfiguration, RechteKonfigurationTK, RechteKonfigurationExchangeContext, DateiImportBerichtCustomData> {

  @Inject
  private transient RechteKonfigurationDAO rechteKonfigurationDAO;

  @Inject
  private transient RechteKonfigurationMeta rechteKonfigurationMeta;

  @Inject
  private transient RechteKonfigurationImportExchange rechteKonfigurationImportExchange;

  @Inject
  private transient RolleCreator rolleCreator;

  @Inject
  private transient RechteKonfigurationAktualisierenEvent rechteKonfigurationAktualisierenEvent;

  @Inject
  private transient RechteKonfigurationCreate rechteKonfigurationCreate;

  public RechteKonfigurationImporter() {
    super();
  }

  @Override
  protected void postImportActions(DateiImport dateiImport,
      RechteKonfigurationExchangeContext rechteKonfigurationExchangeContext, ImportOptions importOptions,
      DateiImportBerichtCustomData customDateiImportBericht) {
    super.postImportActions(dateiImport, rechteKonfigurationExchangeContext, importOptions, customDateiImportBericht);

    rechteKonfigurationDAO.flush(); // damit beim Event alle Rechte in der DB sind...
    rechteKonfigurationAktualisierenEvent.sendChangeEvent();
  }

  @Override
  protected void postImportActions(List<RechteKonfiguration> rechteKonfigurations, RechteKonfigurationExchangeContext context, ImportOptions importOptions, DateiImportBerichtCustomData customDateiImportBericht, StringBuilder bericht) {
    super.postImportActions(rechteKonfigurations, context, importOptions, customDateiImportBericht, bericht);
    rechteKonfigurationDAO.flush();
    rolleCreator.cleanUpProduktivTestRechte(context.getMandant()); // WASDE-1089
  }

  @Override
  protected void persistiere(Collection<RechteKonfiguration> neueEntities, RechteKonfigurationExchangeContext context,
                             DateiImportBerichtCustomData dateiImportBerichtCustomData, StringBuilder bericht) {
    for (RechteKonfiguration neueEntity : neueEntities) {
      neueEntity.setMandant(context.getMandant());
      rechteKonfigurationCreate.save(neueEntity);
    }
  }

  @Override
  protected void aktualisiere(RechteKonfiguration entityInDatei, RechteKonfiguration entityInDatenbank, RechteKonfigurationExchangeContext noContext,
                              DateiImportBerichtCustomData dateiImportBerichtCustomData, StringBuilder bericht) {
    entityInDatenbank.setNurImTestmodusAktiv(entityInDatei.getNurImTestmodusAktiv());
  }

  @Override
  protected void loescheAusDatenbank(Collection<RechteKonfiguration> entitiesInDb, RechteKonfigurationExchangeContext noContext,
                                     DateiImportBerichtCustomData dateiImportBerichtCustomData, StringBuilder bericht) {
    for (RechteKonfiguration rechteKonfiguration : entitiesInDb) {
      // ACHTUNG: RechteKonfiguration sollen nicht aus der Datenbank gelöscht werden, damit die protokollierten Änderungen erhalten bleiben und zuzuordnen sind. 
      rechteKonfiguration.setNurImTestmodusAktiv(false);
    }
  }

  @Override
  protected List<RechteKonfiguration> getAllEntitiesInDB(RechteKonfigurationExchangeContext context) {
    return rechteKonfigurationDAO.findByAll(context.getMandant());
  }

  @Override
  protected Function<RechteKonfiguration, RechteKonfigurationTK> getEntityToEntityTKFunction() {
    return RechteKonfiguration::getRechteKonfigurationTK;
  }

  @Override
  protected void validiere(Violations violations, List<RechteKonfiguration> rechteKonfigurations, RechteKonfigurationExchangeContext noContext, ImportOptions importOptions) {
    for (RechteKonfiguration rechteKonfiguration : rechteKonfigurations) {
      validateEntity(violations, rechteKonfiguration, rechteKonfiguration.getTk());
    }
  }

  /**
   * Erstellt einen individuellen Bericht mit den Zahlen der tatsächlich betroffenen Produktivrechte.
   * <p>
   * ACHTUNG, die Zahlen in diesem Bericht basieren auf der Annahme, dass alle Änderungen übernommen werden.
   */
  @Override
  protected ImportUpdateReport createImportUpdateReport(List<RechteKonfiguration> inDatei, Violations violations,
                                                        RechteKonfigurationExchangeContext context, ImportOptions importOptions, StringBuilder bericht) {
    if (!ImportOptions.IMPORT_VOLLSTAENDIG_UEBERNEHMEN.equals(importOptions)) {
      return super.createImportUpdateReport(inDatei, violations, context, importOptions, bericht);
    }

    List<RechteKonfiguration> inDB = getAllEntitiesInDB(context);
    Set<UseCasePermission> produktivrechteInDB = getProduktivrechte(inDB);
    Set<UseCasePermission> produktivrechteInDatei = getProduktivrechte(inDatei);
    CollectionSeparator<UseCasePermission, UseCasePermission> separator = new CollectionSeparator<>(
        produktivrechteInDatei, produktivrechteInDB, Function.identity());

    return new ImportUpdateReport(violations, separator.getInFirstNotInSecond().size(),
        separator.getInSecondNotInFirst().size(), separator.getInBoth().size(), importOptions, bericht);
  }

  private Set<UseCasePermission> getProduktivrechte(Collection<RechteKonfiguration> rechteKonfigurations) {
    return new HashSet<>(rechteKonfigurations.stream().filter(RechteKonfiguration::getNurImTestmodusAktiv)
        .map(RechteKonfiguration::getRecht).collect(Collectors.toSet()));
  }

  /**
   * Erstellt einen individuellen Bericht mit den Zahlen der tatsächlich betroffenen Produktivrechte.
   * <p>
   * ACHTUNG, die Zahlen in diesem Bericht basieren auf der Annahme, dass alle Änderungen übernommen werden.
   */
  @Override
  protected void erstelleBericht(List<RechteKonfiguration> inDatei, RechteKonfigurationExchangeContext context, ImportOptions importOptions,
                                 StringBuilder bericht, boolean vorab) {
    // nichts zu tun
  }

  @Override
  protected ImportExchange<List<RechteKonfiguration>, RechteKonfigurationExchangeContext> getExchange() {
    return rechteKonfigurationImportExchange;
  }

  @Override
  public Meta getMetaForEntityInternal() {
    return rechteKonfigurationMeta;
  }
}
