package de.ivu.elect.was.sitzberechnung.control;

import de.ivu.elect.business.ergebnis.boundary.SitzeFactory;
import de.ivu.elect.business.ergebnis.entity.ErgebnisLogEintrag;
import de.ivu.elect.business.ergebnis.entity.ErgebnisLogEintragArt;
import de.ivu.elect.business.ergebnis.entity.GewaehltStatus;
import de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt;
import de.ivu.elect.jee.entity.customdata.EmptyCustomData;
import de.ivu.elect.jee.faces.Messages;
import de.ivu.elect.sitzberechnung.Gewaehlt;
import de.ivu.elect.sitzberechnung.SitzberechnungLogeintrag;
import de.ivu.elect.sitzberechnung.Sitzberechnungsergebnis;
import de.ivu.elect.sitzberechnung.Sitze;
import de.ivu.elect.sitzberechnung.konflikt.AbstractErgebnisKonflikt;
import de.ivu.elect.was.sitzberechnung.entity.AbstractSitzberechnungKandidatur;
import de.ivu.elect.was.sitzberechnung.entity.KonfliktMapper;
import de.ivu.elect.was.sitzberechnung.entity.SitzberechnungGebiet;
import de.ivu.elect.was.sitzberechnung.entity.SitzberechnungGruppe;
import de.ivu.elect.was.sitzberechnung.entity.SitzberechnungMappingContext;

import javax.inject.Inject;
import java.util.List;
import java.util.stream.Collectors;

public class SitzberechnungsergebnisMapper {

  @Inject
  transient SitzeFactory sitzeFactory;

  @Inject
  transient Messages messages;


  public de.ivu.elect.business.sitzberechnung.entity.Sitzberechnungsergebnis mappe(Sitzberechnungsergebnis sitzberechnungsergebnis,
                                                                                   KonfliktMapper konfliktMapper, SitzberechnungMappingContext sitzberechnungMappingContext) {
    List<de.ivu.elect.business.ergebnis.entity.Sitze> sitze = mappeSitze(sitzberechnungsergebnis.getSitze());
    List<de.ivu.elect.business.ergebnis.entity.Gewaehlt> gewaehlte = mappeGewaehlte(sitzberechnungsergebnis.getGewaehlte());
    List<de.ivu.elect.business.ergebniskonflikt.entity.ErgebnisKonflikt> konflikte = mappeKonflikte(sitzberechnungsergebnis, konfliktMapper, sitzberechnungMappingContext);
    List<ErgebnisLogEintrag> ergebnisLogEintraege = mappeErgebnisLogEintraege(sitzberechnungsergebnis.getLogEintraege(), sitzberechnungMappingContext);

    return new de.ivu.elect.business.sitzberechnung.entity.Sitzberechnungsergebnis(sitze, gewaehlte, konflikte, ergebnisLogEintraege, "", sitzberechnungsergebnis.getCustomData());
  }

  protected List<ErgebnisLogEintrag> mappeErgebnisLogEintraege(List<SitzberechnungLogeintrag> logEintraege, SitzberechnungMappingContext sitzberechnungMappingContext) {
    return logEintraege.stream().map(this::mappeErgebnisLogEintrag).collect(Collectors.toList());
  }

  private ErgebnisLogEintrag mappeErgebnisLogEintrag(SitzberechnungLogeintrag eintrag) {
    ErgebnisLogEintrag ergebnisLogEintrag = new ErgebnisLogEintrag();
    ergebnisLogEintrag.setErgebnisLogEintragArt(mappeErgebnisLogEintragArt(eintrag.getErgebnisLogEintragArt()));
    ergebnisLogEintrag.setText(messages.getMessageForMessageKey(eintrag.getMessageKey(), eintrag.getObjects()));
    return ergebnisLogEintrag;
  }

  protected ErgebnisLogEintragArt mappeErgebnisLogEintragArt(de.ivu.elect.sitzberechnung.ErgebnisLogEintragArt ergebnisLogEintragArt) {
    try {
      return ErgebnisLogEintragArt.valueOf(ergebnisLogEintragArt.name());
    } catch (IllegalArgumentException iae) {
      throw new IllegalStateException("Die folgende ErgebnisLogEintragArt ist nicht verfügbar: " + ergebnisLogEintragArt, iae);
    }
  }

  private List<ErgebnisKonflikt> mappeKonflikte(Sitzberechnungsergebnis sitzberechnungsergebnis, KonfliktMapper konfliktMapper, SitzberechnungMappingContext sitzberechnungMappingContext) {
    return sitzberechnungsergebnis.getKonflikte().stream()
            .map(k -> mappeKonflikt(k, konfliktMapper, sitzberechnungMappingContext))
            .collect(Collectors.toList());
  }

  private ErgebnisKonflikt mappeKonflikt(de.ivu.elect.sitzberechnung.konflikt.ErgebnisKonflikt konflikt, KonfliktMapper konfliktMapper, SitzberechnungMappingContext sitzberechnungMappingContext) {
    if (konflikt instanceof AbstractErgebnisKonflikt) {
      Object ergebnisKonfliktPersistent = ((AbstractErgebnisKonflikt) konflikt).getErgebnisKonfliktPersistent();
      if (ergebnisKonfliktPersistent instanceof ErgebnisKonflikt) {
        return (ErgebnisKonflikt) ergebnisKonfliktPersistent;
      }
    }
    return konfliktMapper.mappeErgebnis(konflikt, sitzberechnungMappingContext);
  }

  protected List<de.ivu.elect.business.ergebnis.entity.Sitze> mappeSitze(List<Sitze> sitze) {
    return sitze.stream().map(this::mappeSitze).collect(Collectors.toList());
  }

  private de.ivu.elect.business.ergebnis.entity.Sitze mappeSitze(Sitze sbSitze) {
    de.ivu.elect.business.ergebnis.entity.Sitze sitze = sitzeFactory.create();
    sitze.setAnzahl(sbSitze.getAnzahlSitze());
    sitze.setAnzahlAnspruch(sitze.getAnzahl()); // ELECT-9863 todo
    sitze.setGebiet(((SitzberechnungGebiet) sbSitze.getGebiet()).getEntity());
    sitze.setGruppe(((SitzberechnungGruppe) sbSitze.getGruppe()).getEntity());
    return sitze;
  }

  protected List<de.ivu.elect.business.ergebnis.entity.Gewaehlt> mappeGewaehlte(List<Gewaehlt> gewaehlte) {
    return gewaehlte.stream().map(this::mappeGewaehlt).collect(Collectors.toList());
  }

  private de.ivu.elect.business.ergebnis.entity.Gewaehlt mappeGewaehlt(Gewaehlt g) {
    de.ivu.elect.business.ergebnis.entity.Gewaehlt gewaehlt = new de.ivu.elect.business.ergebnis.entity.Gewaehlt(EmptyCustomData.INSTANCE);
    gewaehlt.setKandidatur(((AbstractSitzberechnungKandidatur<?>) g.getKandidatur()).getEntity());
    gewaehlt.setGewaehltStatus(mappeGewaehltStatus(g.getGewaehltStatus()));
    gewaehlt.setRang(g.getRang());
    return gewaehlt;
  }

  protected GewaehltStatus mappeGewaehltStatus(de.ivu.elect.sitzberechnung.GewaehltStatus gewaehltStatus) {
    try {
      return GewaehltStatus.valueOf(gewaehltStatus.name());
    } catch (IllegalArgumentException iae) {
      throw new IllegalStateException("Das folgende Gewähltstatus ist nicht verfügbar: " + gewaehltStatus, iae);
    }
  }

}
