package de.ivu.elect.core.exchange.mapper;

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

import javax.inject.Inject;

import org.apache.commons.lang3.StringUtils;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietTK;
import de.ivu.elect.business.gruppe.boundary.GruppeFactory;
import de.ivu.elect.business.gruppe.entity.Gruppe;
import de.ivu.elect.business.stimmzettel.boundary.StimmzettelFactory;
import de.ivu.elect.business.stimmzettel.entity.Stimmzettel;
import de.ivu.elect.business.stimmzettel.entity.StimmzettelGueltigkeit;
import de.ivu.elect.business.stimmzettel.entity.StimmzettelKopfdatum;
import de.ivu.elect.business.stimmzettel.entity.StimmzettelKopfdatumArt;
import de.ivu.elect.business.stimmzettel.entity.StimmzettelStatus;
import de.ivu.elect.business.stimmzettel.entity.StimmzettelTeam;
import de.ivu.elect.business.stimmzettel.entity.WesStimmzettelDaten;
import de.ivu.elect.business.wahl.boundary.WahlFactory;
import de.ivu.elect.business.wahl.boundary.WahlterminFactory;
import de.ivu.elect.business.wahl.entity.Wahl;
import de.ivu.elect.business.wahl.entity.WahlTK;
import de.ivu.elect.business.wahl.entity.Wahlart;
import de.ivu.elect.exchange.gebietsbaum.mapper.GebietMapper;
import de.ivu.elect.interfaces.core.GebietReferenz;
import de.ivu.elect.interfaces.wes.StimmzettelImGebiet;
import de.ivu.elect.interfaces.wes.Stimmzettelerfassung;
import de.ivu.elect.util.TriFunction;

public class StimmzettelMapper implements Serializable {
  private static final long serialVersionUID = 1L;

  @Inject
  protected transient GebietMapper gebietMapper;

  @Inject
  private transient WahlFactory wahlFactory;

  @Inject
  private transient WahlterminFactory wahlterminFactory;

  @Inject
  private transient GruppeFactory gruppeFactory;

  @Inject
  private transient StimmzettelFactory stimmzettelFactory;

  public void mappeStimmzettel(Stimmzettelerfassung stimmzettelerfassung, Gebiet gebiet, List<Stimmzettel> stimmzettelImGebiet, List<StimmzettelKopfdatum> stimmzettelKopfdatenImGebiet) {
    StimmzettelImGebiet stimmzettelNachGebiet = new StimmzettelImGebiet();
    stimmzettelerfassung.getStimmzettelImGebiet().add(stimmzettelNachGebiet);
    stimmzettelNachGebiet.setGebietReferenz(gebietMapper.getMapperUtil().createGebietReferenz(gebiet));

    for (Stimmzettel stimmzettel : stimmzettelImGebiet) {
      de.ivu.elect.interfaces.wes.Stimmzettel stimmzettel1Extern = new de.ivu.elect.interfaces.wes.Stimmzettel();
      stimmzettelNachGebiet.getErfassteStimmzettel().add(stimmzettel1Extern);
      stimmzettel1Extern.setStatus(stimmzettel.getStatus().name());
      stimmzettel1Extern.setGueltigkeit(stimmzettel.getGueltigkeit().name());
      stimmzettel1Extern.setNummer(stimmzettel.getNummer());
      stimmzettel1Extern.setErfasser(stimmzettel.getErfasser());
      stimmzettel1Extern.setErfassungszeitpunkt(stimmzettel.getErfassungszeitpunkt());
      stimmzettel1Extern.setStimmzettelDaten(stimmzettel.getErfassteDaten());
      stimmzettel1Extern.setBemerkung(stimmzettel.getBemerkung());
      stimmzettel1Extern.setVersionsnummer(stimmzettel.getVersionsnummer());
      stimmzettel1Extern.setStimmzettelTeam(stimmzettel.getStimmzettelTeam().name());
    }

    for (StimmzettelKopfdatum stimmzettelKopfdatum : stimmzettelKopfdatenImGebiet) {
      de.ivu.elect.interfaces.wes.StimmzettelKopfdatum stimmzettelKopfdatumExtern = new de.ivu.elect.interfaces.wes.StimmzettelKopfdatum();
      stimmzettelNachGebiet.getStimmzettelKopfdaten().add(stimmzettelKopfdatumExtern);
      if (stimmzettelKopfdatum.getGruppe() != null) {
        stimmzettelKopfdatumExtern.setGruppeReferenz(gebietMapper.getMapperUtil().createGruppeReferenz(stimmzettelKopfdatum.getGruppe().getSchluessel()));
      }
      stimmzettelKopfdatumExtern.setSchluessel(stimmzettelKopfdatum.getSchluessel());
      stimmzettelKopfdatumExtern.setWert(stimmzettelKopfdatum.getWert());
    }
  }

  public List<WesStimmzettelDaten> mappe(Stimmzettelerfassung stimmzettelerfassung, TriFunction<WahlTK, GebietTK, String, String> signieraturFct) {

    Wahl wahl = wahlFactory.create();
    wahl.setWahlart(new Wahlart());
    wahl.getWahlart().setName(stimmzettelerfassung.getWahlart());
    wahl.setWahltermin(wahlterminFactory.create());
    wahl.getWahltermin().setWahldatum(stimmzettelerfassung.getWahldatum());
    wahl.getWahltermin().setNummer(stimmzettelerfassung.getWahlterminNummer());

    List<WesStimmzettelDaten> result = new ArrayList<>();

    for (StimmzettelImGebiet stimmzettelImGebiet : stimmzettelerfassung.getStimmzettelImGebiet()) {

      HashMap<GebietReferenz, Gebiet> gebieteNachReferenz = new HashMap<>();
      Gebiet gebiet = gebietMapper.mapGebietReferenz(stimmzettelImGebiet.getGebietReferenz(), gebieteNachReferenz);
      gebiet.setWahl(wahl);
      Long versionsnummer = null;
      List<StimmzettelKopfdatum> stimmzettelKopfdaten = new ArrayList<>();
      for (de.ivu.elect.interfaces.wes.StimmzettelKopfdatum stimmzettelKopfdatumExtern : stimmzettelImGebiet.getStimmzettelKopfdaten()) {
        StimmzettelKopfdatum stimmzettelKopfdatumIntern = new StimmzettelKopfdatum();
        stimmzettelKopfdaten.add(stimmzettelKopfdatumIntern);
        stimmzettelKopfdatumIntern.setSchluessel(stimmzettelKopfdatumExtern.getSchluessel());
        stimmzettelKopfdatumIntern.setWert(stimmzettelKopfdatumExtern.getWert());
        stimmzettelKopfdatumIntern.setGebiet(gebiet);
        if (stimmzettelKopfdatumExtern.getGruppeReferenz() != null && StringUtils.isNotBlank(stimmzettelKopfdatumExtern.getGruppeReferenz().getSchluessel())) {
          Gruppe gruppe = gruppeFactory.create();
          gruppe.setSchluessel(stimmzettelKopfdatumExtern.getGruppeReferenz().getSchluessel());
          stimmzettelKopfdatumIntern.setGruppe(gruppe);
        }

        if (StimmzettelKopfdatumArt.VERSIONSNUMMER.equals(stimmzettelKopfdatumIntern.getStimmzettelKopfdatumArt())) {
          versionsnummer = stimmzettelKopfdatumIntern.parseWertAsLong();
        }
      }

      List<Stimmzettel> stimmzettelList = new ArrayList<>();
      for (de.ivu.elect.interfaces.wes.Stimmzettel stimmzettelExtern : stimmzettelImGebiet.getErfassteStimmzettel()) {
        Stimmzettel stimmzettelIntern = mappe(stimmzettelExtern);
        stimmzettelIntern.setGebiet(gebiet);
        stimmzettelList.add(stimmzettelIntern);
      }
      Boolean signaturGueltig = null;

      String signatur = signieraturFct.apply(wahl.getWahlTK(), gebiet.getGebietTK(), stimmzettelImGebiet.getZuSignierendeDaten());
      if (StringUtils.isNotBlank(signatur)) {
        signaturGueltig = signatur.equals(stimmzettelImGebiet.getSignatur());
      }

      result.add(new WesStimmzettelDaten(gebiet, stimmzettelKopfdaten, stimmzettelList, versionsnummer, signaturGueltig));
    }

    return result;

  }

  public Stimmzettel mappe(de.ivu.elect.interfaces.wes.Stimmzettel stimmzettelExtern) {
    Stimmzettel stimmzettelIntern = stimmzettelFactory.create();
    stimmzettelIntern.setStatus(StimmzettelStatus.valueOf(stimmzettelExtern.getStatus()));
    stimmzettelIntern.setGueltigkeit(mappeStimmzettelGueltigkeit(stimmzettelExtern.getGueltigkeit()));
    stimmzettelIntern.setNummer(stimmzettelExtern.getNummer());
    stimmzettelIntern.setErfasser(stimmzettelExtern.getErfasser());
    stimmzettelIntern.setErfassungszeitpunkt(stimmzettelExtern.getErfassungszeitpunkt());
    stimmzettelIntern.setErfasssteDaten(stimmzettelExtern.getStimmzettelDaten());
    stimmzettelIntern.setBemerkung(stimmzettelExtern.getBemerkung());
    stimmzettelIntern.setStimmzettelTeam(bestimmeTeam(stimmzettelExtern.getStimmzettelTeam()));
    if (stimmzettelExtern.getVersionsnummer()!=null) {
      // ELECT-9509
      stimmzettelIntern.setVersionsnummer(stimmzettelExtern.getVersionsnummer());
    }
    return stimmzettelIntern;
  }

  protected StimmzettelGueltigkeit mappeStimmzettelGueltigkeit(String gueltigkeit) {
    try  {
      return StimmzettelGueltigkeit.valueOf(gueltigkeit);
    } catch (Exception e){
      // ELECTKOM-743 Abwärtskompatibilität
      if ("UNGUELTIG".equals(gueltigkeit)) {
        return StimmzettelGueltigkeit.UNGUELTIG_PER_BESCHLUSS;
      }
      throw e;
    }


  }

  private StimmzettelTeam bestimmeTeam(String stimmzettelTeam) {
    if (StringUtils.isBlank(stimmzettelTeam)) {
      return StimmzettelTeam.UNBEKANNT;
    }

    try {
      return StimmzettelTeam.valueOf(stimmzettelTeam);
    } catch (Exception e) {
      return StimmzettelTeam.UNBEKANNT;
    }

  }

}
