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

import java.util.Collection;
import java.util.Optional;

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

import de.ivu.elect.business.entschaedigung.control.AuszahlungProtokollierungEntschaedigung;
import de.ivu.elect.business.entschaedigung.control.EntschaedigungAggregator;
import de.ivu.elect.business.entschaedigung.control.EntschaedigungCreate;
import de.ivu.elect.business.entschaedigung.entity.Auszahlung;
import de.ivu.elect.business.entschaedigung.entity.Entschaedigung;
import de.ivu.elect.business.entschaedigung.entity.Entschaedigungsart;
import de.ivu.elect.business.person.boundary.PersonendatenDAO;
import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.Wahltermin;
import de.ivu.elect.jee.faces.Messages;

@Stateless
public class EntschaedigungInAuszahlungBulkCreate {

  @Inject
  private transient Messages messages;

  @Inject
  private transient PersonendatenDAO personendatenDAO;

  @Inject
  private transient EntschaedigungsartDAO entschaedigungsartDAO;

  @Inject
  private transient AuszahlungDAO auszahlungDAO;

  @Inject
  private transient EntschaedigungDAO entschaedigungDAO;

  @Inject
  private transient EntschaedigungFactory entschaedigungFactory;

  @Inject
  private transient EntschaedigungCalculator entschaedigungCalculator;

  @Inject
  private transient EntschaedigungCreate entschaedigungCreate;

  public EntschaedigungInAuszahlungBulkCreate() {
    super();
  }

  public void saveEntschaedigungenInAuszahlung(EntschaedigungInAuszahlungBulkCreateParameters entschaedigungInAuszahlungBulkCreateParameters) {
    Auszahlung auszahlung = attach(entschaedigungInAuszahlungBulkCreateParameters.getAuszahlung());

    EntschaedigungAggregator entschaedigungenInAuszahlungAggregator = auszahlung.createEntschaedigungenAggregator(entschaedigungDAO);

    Collection<Entschaedigung> entschaedigungen = calculateEntschaedigungen(auszahlung.getWahl(), auszahlung.getWahltermin(), entschaedigungInAuszahlungBulkCreateParameters);

    for (Entschaedigung entschaedigung : entschaedigungen) {
      createOrUpdateEntschaedigungInAuszahlung(entschaedigungenInAuszahlungAggregator, auszahlung, entschaedigung);
    }

    if (!entschaedigungen.isEmpty()) {
      AuszahlungProtokollierungEntschaedigung.protokolliereCreate(auszahlung, messages);
    }
  }

  private Entschaedigung createOrUpdateEntschaedigungInAuszahlung(EntschaedigungAggregator entschaedigungenInAuszahlungAggregator, Auszahlung auszahlung, Entschaedigung entschaedigung) {
    Personendaten personendaten = attach(entschaedigung.getPersonendaten());
    Entschaedigungsart entschaedigungsart = attach(entschaedigung.getEntschaedigungsart());

    Optional<Entschaedigung> entschaedigungInAuszahlungIfPresent = entschaedigungenInAuszahlungAggregator.findEntschaedigungByEntschaedigungsart(personendaten, entschaedigungsart);

    if (entschaedigungInAuszahlungIfPresent.isPresent()) {
      Entschaedigung entschaedigungInAuszahlungUpdated = entschaedigungInAuszahlungIfPresent.get();
      entschaedigungInAuszahlungUpdated.copyEntschaedigungDetailsFrom(entschaedigung);

      return entschaedigungInAuszahlungUpdated;
    }

    Entschaedigung entschaedigungInAuszahlungCreated = entschaedigungFactory.create();
    entschaedigungInAuszahlungCreated.copyEntschaedigungDetailsFrom(entschaedigung);
    entschaedigungInAuszahlungCreated.setAuszahlung(auszahlung);
    entschaedigungInAuszahlungCreated.setPersonendaten(personendaten);
    entschaedigungInAuszahlungCreated.setEntschaedigungsart(entschaedigungsart);

    entschaedigungCreate.save(entschaedigungInAuszahlungCreated);

    return entschaedigungInAuszahlungCreated;
  }

  private Collection<Entschaedigung> calculateEntschaedigungen(Wahl wahl, Wahltermin wahltermin, EntschaedigungToCalculateParameters entschaedigungToCalculateParameters) {
    entschaedigungToCalculateParameters.setWahl(wahl);
    entschaedigungToCalculateParameters.setWahltermin(wahltermin);
    entschaedigungToCalculateParameters.setEntschaedigungKriteriumGesamtbetrag(EntschaedigungKriteriumGesamtbetrag.NUR_GROESSER_NULL);

    return entschaedigungCalculator.calculateEntschaedigungen(entschaedigungToCalculateParameters);
  }

  private Entschaedigungsart attach(Entschaedigungsart entschaedigungsart) {
    return entschaedigungsartDAO.attach(entschaedigungsart);
  }

  private Personendaten attach(Personendaten personendaten) {
    return personendatenDAO.attach(personendaten);
  }

  private Auszahlung attach(Auszahlung auszahlung) {
    return auszahlungDAO.attach(auszahlung);
  }
}
