
package de.ivu.elect.presentation.personenpruefung;

import static java.util.Arrays.asList;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.inject.Inject;

import de.ivu.elect.business.person.entity.Personendaten;
import de.ivu.elect.business.personenpruefung.control.PersonendatenMatcherKriterium;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.AbstractPersonendatenWahlrechtMatcher;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.kriterium.HoechstalterAmStichtagKriterium;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.kriterium.MindestalterAmStichtagKriterium;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.kriterium.MindestaufenthaltAnAnschriftArtInGebietAmStichtagKriterium;
import de.ivu.elect.business.personenpruefung.control.wahlrecht.kriterium.PersonenregisterAbgleichbarkeitKriterium;
import de.ivu.elect.jee.faces.Messages;

public class PersonendatenWahlrechtKriteriumFormatter implements Serializable {

  private static final long serialVersionUID = 1L;

  @Inject
  private transient Messages messages;

  public PersonendatenWahlrechtKriteriumFormatter() {
    super();
  }

  public List<PersonendatenMatcherKriteriumFormatted> formatKriterienFailed(AbstractPersonendatenWahlrechtMatcher matcher, Personendaten personendaten) {
    List<PersonendatenMatcherKriteriumFormatted> result = new ArrayList<>();

    List<MindestalterAmStichtagKriterium> mindestalterAmStichtagKriterien = new ArrayList<>(matcher.collectMindestalterAmStichtagKriterien(personendaten));
    Collections.sort(mindestalterAmStichtagKriterien);

    List<HoechstalterAmStichtagKriterium> hoechstalterAmStichtagKriterien = new ArrayList<>(matcher.collectHoechstalterAmStichtagKriterien(personendaten));
    Collections.sort(hoechstalterAmStichtagKriterien);

    addKriteriumFailedFormatted(result, personendaten, mindestalterAmStichtagKriterien);
    addKriteriumFailedFormatted(result, personendaten, hoechstalterAmStichtagKriterien);

    addKriteriumFailedFormatted(result, personendaten, matcher.collectStaatsangehoerigkeitKriterien(personendaten));

    if (!matcher.matchesWahlrechtsauschluesse(personendaten)) {
      addKriteriumFailedFormatted(result, personendaten, matcher.collectWahlrechtsausschlussKriterien(personendaten));
    }

    PersonenregisterAbgleichbarkeitKriterium personenregisterAbgleichbarkeitKriterium = matcher.collectPersonenregisterAbgleichbarkeitKriterium(personendaten);
    boolean personenregisterAbgleichbarkeitRelevant = !personenregisterAbgleichbarkeitKriterium.getWahlrechtPersonenregisterAbgleichbarkeit().isIrrelevant();

    if (personenregisterAbgleichbarkeitRelevant) {
      addKriteriumFailedFormatted(result, personendaten, asList(personenregisterAbgleichbarkeitKriterium));
    }

    List<MindestaufenthaltAnAnschriftArtInGebietAmStichtagKriterium> mindestaufenthaltAnAnschriftArtInGebietAmStichtagKriterien = matcher
        .collectMindestaufenthaltAnAnschriftArtInGebietAmStichtagKriterien(personendaten);
    boolean mindestaufenthaltAnAnschriftArtInGebietAmStichtagRelevant = !mindestaufenthaltAnAnschriftArtInGebietAmStichtagKriterien.isEmpty();

    if (personenregisterAbgleichbarkeitRelevant || mindestaufenthaltAnAnschriftArtInGebietAmStichtagRelevant) {
      addKriteriumFailedFormatted(result, personendaten, mindestaufenthaltAnAnschriftArtInGebietAmStichtagKriterien);
    }

    addKriteriumFailedFormatted(result, personendaten, matcher.collectWahlrechtGebietsartInReferenzGebietKriterien(personendaten));

    return result;
  }

  private void addKriteriumFailedFormatted(List<PersonendatenMatcherKriteriumFormatted> result, Personendaten personendaten, List< ? extends PersonendatenMatcherKriterium> kriterien) {
    kriterien.forEach(kriterium -> {
      if (kriterium.matchesNot(personendaten)) {
        result.add(new PersonendatenMatcherKriteriumFormatted(kriterium.getLabel(getMessages()), kriterium.getDescription(getMessages())));
      }
    });
  }

  private Messages getMessages() {
    return messages;
  }
}
