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

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

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

import de.ivu.elect.business.gebietsbaum.boundary.GebietDAO;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gruppe.control.PolitischeGruppeCreate;
import de.ivu.elect.business.gruppe.entity.PolitischeGruppe;
import de.ivu.elect.business.gruppeimgebiet.control.GruppeImGebietUniquePositionValidator;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahlvorschlag.boundary.ReferendumOptionFactory;
import de.ivu.elect.business.wahlvorschlag.control.ReferendumOptionCreate;
import de.ivu.elect.business.wahlvorschlag.entity.ReferendumOption;
import de.ivu.elect.business.wahlvorschlag.entity.ReferendumOptionConstants;
import de.ivu.elect.business.wahlvorschlag.entity.WahlvorschlagStatus;
import de.ivu.elect.jee.faces.Messages;

@Stateless
public class ReferendumVorlageImGebietCreate {

  @Inject
  private transient GebietDAO gebietDao;

  @Inject
  private transient ReferendumOptionFactory referendumOptionFactory;

  @Inject
  private transient ReferendumOptionCreate referendumOptionCreate;

  @Inject
  private transient PolitischeGruppeCreate politischeGruppeCreate;

  @Inject
  private transient GruppeImGebietHierarchyBuilder gruppeImGebietHierarchyBuilder;

  @Inject
  private transient GruppeImGebietUniquePositionValidator gruppeImGebietUniquePositionValidator;

  @Inject
  private transient Messages messages;

  public ReferendumVorlageImGebietCreate() {
    super();
  }

  public void save(GruppeImGebiet referendumVorlageImGebiet) {
    save((PolitischeGruppe) referendumVorlageImGebiet.getGruppe(), attach(referendumVorlageImGebiet.getGebiet()), referendumVorlageImGebiet);
  }

  private void save(PolitischeGruppe referendumVorlage, Gebiet gebiet, GruppeImGebiet referendumVorlageImGebiet) {
    assertUniqueGruppeImGebietPosition(referendumVorlageImGebiet);

    save(referendumVorlage);
    saveAndCompleteHierarchy(referendumVorlageImGebiet);

    if (referendumVorlage.getReferendumOptionen().isEmpty()) {
      saveDefaultReferendumOptionen(gebiet.getWahl(), referendumVorlageImGebiet);
    }
  }

  private void assertUniqueGruppeImGebietPosition(GruppeImGebiet gruppeImGebiet) {
    if (!gruppeImGebietUniquePositionValidator.isValid(gruppeImGebiet)) {
      throw new IllegalArgumentException("Position der GruppeImGebiet einer Vorlage eines Referendums muss eineindetig sein [wahl = " + gruppeImGebiet.getWahl() + ", gruppeImGebiet = "
          + gruppeImGebiet + ", position = " + gruppeImGebiet.getRelativePosition() + "]");
    }
  }

  private void save(PolitischeGruppe politischeGruppe) {
    politischeGruppeCreate.save(politischeGruppe);
  }

  private void saveAndCompleteHierarchy(GruppeImGebiet gruppeImGebiet) {
    gruppeImGebietHierarchyBuilder.saveAndCompleteHierarchy(gruppeImGebiet);
  }

  private void saveDefaultReferendumOptionen(Wahl wahl, GruppeImGebiet referendumVorlageImGebiet) {
    List<Boolean> defaultValues = new ArrayList<>();
    defaultValues.add(Boolean.TRUE);

    // NOTE, dass Begehren, bspw. Volksbegehren, 1.Stufe, nur eine positive Option als auswählbaren Wahlvorschlag benötigen.
    if (wahl.isReferendum()) {
      defaultValues.add(Boolean.FALSE);
    }

    Date zeitpunktDerEinreichung = new Date();

    for (Boolean value : defaultValues) {
      ReferendumOption referendumOption = createReferendumOption();

      referendumOption.setGruppeImGebiet(referendumVorlageImGebiet);
      referendumOption.setWahlvorschlagStatus(WahlvorschlagStatus.ZUGELASSEN);
      referendumOption.setLabel(getDefaultLabel(value));
      referendumOption.setKurzbezeichnung(getDefaultLabel(value));
      referendumOption.setZeitpunktDerEinreichung(zeitpunktDerEinreichung);
      referendumOption.setPosition(defaultValues.indexOf(value) + 1L);

      if (wahl.isBegehren() && referendumOption.getUnterstuetzerErfassbarAb() == null) { // ELECT-3914
        referendumOption.setUnterstuetzerErfassbarAb(zeitpunktDerEinreichung);
      }

      save(referendumOption);
    }
  }

  private void save(ReferendumOption referendumOption) {
    referendumOptionCreate.save(referendumOption);
  }

  private ReferendumOption createReferendumOption() {
    return referendumOptionFactory.create();
  }

  private String getDefaultLabel(Boolean value) {
    return getMessage(ReferendumOptionConstants.MESSAGE_KEY_LABEL_EINZAHL + ".DEFAULT." + value);
  }

  private Gebiet attach(Gebiet gebiet) {
    return gebietDao.attach(gebiet);
  }

  private String getMessage(String msgKey, Object... params) {
    return messages.getMessageForMessageKey(msgKey, params);
  }
}
