package de.ivu.elect.business.stimmeingabe.entity;

import de.ivu.elect.business.gebietsbaum.entity.Gebiet;
import de.ivu.elect.business.gebietsbaum.entity.GebietTK;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebietTK;
import de.ivu.elect.business.kandidatur.control.ListenkandidaturNamenUndListeTK;
import de.ivu.elect.business.kandidatur.entity.Listenkandidatur;
import de.ivu.elect.business.kandidatur.entity.ListenkandidaturTK;
import de.ivu.elect.business.stimmeingabe.control.StimmeingabeImporterHelper;
import de.ivu.elect.business.wahlvorschlag.entity.ListeTK;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.Map;

public interface StimmeingabeImporterListenkandidaturErsetzenStrategie {

  Logger LOG = LoggerFactory.getLogger(StimmeingabeImporterListenkandidaturErsetzenStrategie.class);

  String LISTENKANDIDATUREN_AUF_GEBIET = "StimmeingabeImporterListenkandidaturErsetzenStrategie-listenkandidaturenAufGebiet";

  default void tauscheListenKandidatur(Stimmeingabe stimmeingabe,
                                       Map<ListenkandidaturTK, Listenkandidatur> listenkandidaturenInDbNachListenkandidaturTk,
                                       Map<ListenkandidaturNamenUndListeTK, Listenkandidatur> listenkandidaturenInDbNachNamenUndListeTk,
                                       Map<Listenkandidatur, ListenkandidaturTK> listenkandidaturAusDateiTKCache,
                                       Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb,
                                       StimmeingabeImporterGigContext gigInDbContext,
                                       StimmeingabeImporterHelper stimmeingabeImporterHelper,
                                       StimmeingabeImportUmgangNichtZugelasseneKandidaten umgangNichtZugelasseneKandidaten) {
    var listenkandidaturInDatei = stimmeingabe.getListenkandidatur();
    if (listenkandidaturInDatei == null) {
      return;
    }

    var listenkandidaturTk = listenkandidaturAusDateiTKCache.computeIfAbsent(listenkandidaturInDatei, Listenkandidatur::getListenkandidaturTK);

    var listenkandidaturInDb = findeListenkandidatur(stimmeingabe.getGebiet(), listenkandidaturTk, listenkandidaturInDatei,
        listenkandidaturenInDbNachListenkandidaturTk, listenkandidaturenInDbNachNamenUndListeTk, gruppenImGebietInDb, gigInDbContext,
        stimmeingabeImporterHelper, umgangNichtZugelasseneKandidaten);
    // ELECTDD-124
    if (listenkandidaturInDb != null) {
      listenkandidaturAusDateiTKCache.put(listenkandidaturInDatei, listenkandidaturInDb.getListenkandidaturTK());
    }

    stimmeingabe.setListenkandidatur(listenkandidaturInDb);
  }

  @Nullable
  default Listenkandidatur findeListenkandidatur(Gebiet erfassungsgebiet,
                                                 ListenkandidaturTK listenkandidaturTk,
                                                 Listenkandidatur listenkandidaturInDatei,

                                                 Map<ListenkandidaturTK, Listenkandidatur> listenkandidaturenInDbNachListenkandidaturTk,
                                                 Map<ListenkandidaturNamenUndListeTK, Listenkandidatur> listenkandidaturenInDbNachNamenUndListeTk,

                                                 Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb,
                                                 StimmeingabeImporterGigContext gigInDbContext,
                                                 StimmeingabeImporterHelper stimmeingabeImporterHelper,
                                                 StimmeingabeImportUmgangNichtZugelasseneKandidaten umgangNichtZugelasseneKandidaten) {

    var listenkandidatur = findeListenkandidaturInternal(erfassungsgebiet,
        listenkandidaturTk,
        listenkandidaturInDatei,
        listenkandidaturenInDbNachListenkandidaturTk,
        listenkandidaturenInDbNachNamenUndListeTk,
        gruppenImGebietInDb,
        gigInDbContext,
        stimmeingabeImporterHelper);

    // ELECT-16597 (!)
    if (listenkandidatur == null) {
      var listenkandidaturenInDb = new HashSet<>(listenkandidaturenInDbNachListenkandidaturTk.values());
      var gebietInDBListenkandidaturInDatei = findeGebiet(erfassungsgebiet, listenkandidaturTk.getListeTK().getGruppeImGebietTK().getGebietTK());
      if (gebietInDBListenkandidaturInDatei != null) {
        LOG.info("Erstelle ListenkandidaturTKs für Gebiet: " + gebietInDBListenkandidaturInDatei);
        for (var lkInDb : listenkandidaturenInDb) {
          if (lkInDb.getGebiet().isInGebietshierarchieUebergeordnetesGebietVon(gebietInDBListenkandidaturInDatei)) {
            var listenkandidaturTK = lkInDb.getListenkandidaturTK();
            var listeTK = listenkandidaturTK.getListeTK();
            var gruppeImGebietTK = listeTK.getGruppeImGebietTK();
            var lkTkNeu = new ListenkandidaturTK(listenkandidaturTK.getRelativePosition(), new ListeTK(listeTK.getDiscriminator(), new GruppeImGebietTK(gebietInDBListenkandidaturInDatei.getGebietTK(), gruppeImGebietTK.getGruppeTK())));
            if (!listenkandidaturenInDbNachListenkandidaturTk.containsKey(lkTkNeu)) {
              listenkandidaturenInDbNachListenkandidaturTk.put(lkTkNeu, lkInDb);
            }
            var listenkandidaturNamenUndListeTKNeu = new ListenkandidaturNamenUndListeTK(lkInDb, lkTkNeu.getListeTK());
            if (!listenkandidaturenInDbNachNamenUndListeTk.containsKey(listenkandidaturNamenUndListeTKNeu)) {
              listenkandidaturenInDbNachNamenUndListeTk.put(listenkandidaturNamenUndListeTKNeu, lkInDb);
            }
          }
        }

        // nächster Versuch
        listenkandidatur = findeListenkandidaturInternal(erfassungsgebiet,
            listenkandidaturTk,
            listenkandidaturInDatei,
            listenkandidaturenInDbNachListenkandidaturTk,
            listenkandidaturenInDbNachNamenUndListeTk,
            gruppenImGebietInDb,
            gigInDbContext,
            stimmeingabeImporterHelper);
      }
    }


    if (listenkandidatur != null && !listenkandidatur.getKandidaturStatus().isZugelassen() && umgangNichtZugelasseneKandidaten.isAlsFehlendBetrachten()) {
      return null;
    }
    return listenkandidatur;
  }

  @Nullable
  static Gebiet findeGebiet(Gebiet gebiet, GebietTK gebietTK) {
    if (gebiet == null) {
      return null;
    }
    if (gebiet.getGebietTK().equals(gebietTK)) {
      return gebiet;
    }
    return findeGebiet(gebiet.getUebergeordnetesGebiet(), gebietTK);
  }

  @Nullable
  Listenkandidatur findeListenkandidaturInternal(Gebiet erfassungsgebiet,
                                                 ListenkandidaturTK listenkandidaturTk,
                                                 Listenkandidatur listenkandidaturInDatei,
                                                 Map<ListenkandidaturTK, Listenkandidatur> listenkandidaturenInDbNachListenkandidaturTk,
                                                 Map<ListenkandidaturNamenUndListeTK, Listenkandidatur> listenkandidaturenInDbNachNamenUndListeTk,
                                                 Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb,
                                                 StimmeingabeImporterGigContext gigInDbContext,
                                                 StimmeingabeImporterHelper stimmeingabeImporterHelper);

}
