
package de.ivu.elect.presentation.kandidatur.table;

import static org.apache.commons.lang3.StringUtils.isBlank;

import java.util.Collection;
import java.util.Comparator;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import de.ivu.elect.business.gebietsbaum.control.GebietByBreadthFirstComparator;
import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.kandidatur.boundary.KandidaturExtendedDAO;
import de.ivu.elect.business.kandidatur.entity.Kandidatur;
import de.ivu.elect.jee.cdi.BeanManagerUtil;
import de.ivu.elect.jee.entity.EagerLoading;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.jee.presentation.dynamictable.ColumnType;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;
import de.ivu.elect.presentation.security.AbstractGebietSecurityFilter;

public abstract class AbstractKandidaturVerknuepfungColumn extends AbstractKandidaturColumn<Kandidatur> {

  private static final long serialVersionUID = 1L;

  private final AbstractGebietSecurityFilter<Kandidatur> gebietSecurityFilter;

  private final GebietNummerFormatter gebietNummerFormatter;

  protected AbstractKandidaturVerknuepfungColumn(String id, Messages messages, String headerKey, AbstractGebietSecurityFilter<Kandidatur> gebietSecurityFilter,
      GebietNummerFormatter gebietNummerFormatter) {
    super(id, messages, headerKey, ColumnType.COLLECTION, null);

    this.gebietSecurityFilter = gebietSecurityFilter;

    this.gebietNummerFormatter = gebietNummerFormatter;
  }

  protected String getNummer(Gebiet gebiet) {
    return gebietNummerFormatter.getNummer(gebiet);
  }

  protected String getNameNummer(Gebiet gebiet) {
    return gebietNummerFormatter.getNameMitNummer(gebiet);
  }

  @Override
  public Object getValue(Kandidatur template) {
    Kandidatur kandidatur = attach(template); // ELECT-8857

    return collectKandidaturenVerknuepft(kandidatur).stream() //
        .filter(getKandidaturVerknuepftFilter()) //
        .sorted(getKandidaturVerknuepftComparator()) //
        .map(kandidaturVerknuepft -> getKandidaturVerknuepftFormatted(kandidatur, kandidaturVerknuepft)) //
        .filter(value -> !isBlank(value)) //
        .collect(Collectors.toList());
  }

  protected Collection< ? extends Kandidatur> collectKandidaturenVerknuepft(Kandidatur kandidatur) {
    return kandidatur.getIdentischVerknuepfteKandidaturen();
  }

  // ELECT-11053
  private Predicate< ? super Kandidatur> getKandidaturVerknuepftFilter() {
    return verknuepfteKandidatur -> verknuepfteKandidatur != null && gebietSecurityFilter.isRechtVorhanden(verknuepfteKandidatur);
  }

  private Comparator< ? super Kandidatur> getKandidaturVerknuepftComparator() {
    return (one, another) -> {
      // identisch und beide Null => gleich
      if (Objects.equals(one.getGebiet(), another.getGebiet())) {
        return 0;
      }

      if (one.getGebiet() == null) {
        return 1;
      }

      if (another.getGebiet() == null) {
        return -1;
      }

      return GebietByBreadthFirstComparator.INSTANCE.compare(one.getGebiet(), another.getGebiet());
    };
  }

  protected abstract String getKandidaturVerknuepftFormatted(Kandidatur kandidatur, Kandidatur kandidaturVerknuepft);

  @Override
  public EagerLoading<Kandidatur> getEagerLoading() {
    EagerLoading<Kandidatur> defaultEagerLoading = super.getEagerLoading();

    return kandidatur -> {
      if (defaultEagerLoading != null) {
        defaultEagerLoading.eagerLoad(kandidatur);

        for (Kandidatur kandidaturVerknuepft : collectKandidaturenVerknuepft(kandidatur)) {
          defaultEagerLoading.eagerLoad(kandidaturVerknuepft);
        }
      }

      return kandidatur;
    };
  }

  private Kandidatur attach(Kandidatur template) {
    return BeanManagerUtil.getBeanByClass(KandidaturExtendedDAO.class).attach(template);
  }
}
