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

import java.util.Map;

import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebiet;
import de.ivu.elect.business.gruppeimgebiet.entity.GruppeImGebietTK;
import de.ivu.elect.business.stimmeingabe.control.StimmeingabeImportContext;
import de.ivu.elect.business.stimmeingabe.control.StimmeingabeImporterHelper;
import de.ivu.elect.business.wahl.entity.Wahldurchfuehrung;
import de.ivu.elect.jee.exchange.Violations;
import de.ivu.elect.presentation.gebietsbaum.GebietNummerFormatter;


import static java.util.Objects.nonNull;

public enum StandardStimmeingabeImporterGruppeImGebietErsetzenStrategie implements StimmeingabeImporterGruppeImGebietErsetzenStrategie {

  ERSETZE_GRUPPE_IM_GEBIET_NACH_TK {
    @Override
    protected GruppeImGebiet findGruppeImGebiet(GruppeImGebiet gruppeImGebietAusDatei, Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb, StimmeingabeImporterGigContext gigInDbContext,
                                                StimmeingabeImporterHelper stimmeingabeImporterHelper) {
      // Suche über Gruppenschlüssel (wie bisher)
      return stimmeingabeImporterHelper.findGruppeImGebietBySchluessel(gruppeImGebietAusDatei, gruppenImGebietInDb, gigInDbContext);
    }
  },
  ERSETZE_GRUPPE_IM_GEBIET_NACH_TK_FALLBACK_POSITION {
    @Override
    protected GruppeImGebiet findGruppeImGebiet(GruppeImGebiet gruppeImGebietAusDatei, Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb, StimmeingabeImporterGigContext gigInDbContext,
                                                StimmeingabeImporterHelper stimmeingabeImporterHelper) {
      // Suche über Gruppenschlüssel (wie bisher)
      var gruppeImGebiet = ERSETZE_GRUPPE_IM_GEBIET_NACH_TK.findGruppeImGebiet(gruppeImGebietAusDatei, gruppenImGebietInDb, gigInDbContext,
          stimmeingabeImporterHelper);

      if (nonNull(gruppeImGebiet)) {
        return gruppeImGebiet;
      }

      // Fallback: Suche über Position (ELECT-6019)
      return ERSETZE_GRUPPE_IM_GEBIET_NACH_POSITION.findGruppeImGebiet(gruppeImGebietAusDatei, gruppenImGebietInDb, gigInDbContext, stimmeingabeImporterHelper);
    }

  },
  ERSETZE_GRUPPE_IM_GEBIET_NACH_POSITION {
    @Override
    protected GruppeImGebiet findGruppeImGebiet(GruppeImGebiet gruppeImGebietAusDatei, Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb, StimmeingabeImporterGigContext gigInDbContext,
                                                StimmeingabeImporterHelper stimmeingabeImporterHelper) {
      return stimmeingabeImporterHelper.findGruppeImGebietByPosition(gruppeImGebietAusDatei, gigInDbContext);
    }
  },

  ERSETZE_GRUPPE_IM_GEBIET_NACH_POSITION_SYSTEMGRUPPE_NACH_TK {
    @Override
    protected GruppeImGebiet findGruppeImGebiet(GruppeImGebiet gruppeImGebietAusDatei, Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb, StimmeingabeImporterGigContext gigInDbContext,
                                                StimmeingabeImporterHelper stimmeingabeImporterHelper) {
      if (gruppeImGebietAusDatei.getGruppe().isSystemGruppe()) {
        return ERSETZE_GRUPPE_IM_GEBIET_NACH_TK.findGruppeImGebiet(gruppeImGebietAusDatei, gruppenImGebietInDb, gigInDbContext, stimmeingabeImporterHelper);
      }
      return ERSETZE_GRUPPE_IM_GEBIET_NACH_POSITION.findGruppeImGebiet(gruppeImGebietAusDatei, gruppenImGebietInDb, gigInDbContext, stimmeingabeImporterHelper);
    }
  };

  @Override
  public void tauscheGruppeImGebiet(Wahldurchfuehrung wahldurchfuehrung, Stimmeingabe stimmeingabe, Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb,
                                    StimmeingabeImporterGigContext gigInDbContext, StimmeingabeImportContext stimmeingabeImportContext, StimmeingabeImporterHelper stimmeingabeImporterHelper) {
    var gruppeImGebietAusDatei = stimmeingabe.getGruppeImGebiet();

    if (gruppeImGebietAusDatei == null) {
      return;
    }

    stimmeingabe.setGruppeImGebiet(findGruppeImGebiet(gruppeImGebietAusDatei, gruppenImGebietInDb, gigInDbContext, stimmeingabeImporterHelper));
  }

  protected abstract GruppeImGebiet findGruppeImGebiet(GruppeImGebiet gruppeImGebietAusDatei,
                                                       Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb,
                                                       StimmeingabeImporterGigContext gigInDbContext,
                                                       StimmeingabeImporterHelper stimmeingabeImporterHelper);

  @Override
  public void pruefeGruppeImGebiet(Wahldurchfuehrung wahldurchfuehrung,
                                   Violations violations,
                                   Map<GruppeImGebietTK, GruppeImGebiet> gruppenImGebietInDb,
                                   Stimmeingabe stimmeingabe,
                                   StimmeingabeImporterGigContext gruppenImGebietInDbContext,
                                   StimmeingabeImportContext stimmeingabeImportContext,
                                   StimmeingabeImporterHelper stimmeingabeImporterHelper,
                                   GebietNummerFormatter gebietNummerFormatter) {

    var gruppeImGebiet = stimmeingabe.getGruppeImGebiet();

    if (gruppeImGebiet != null) {
      var gruppeImGebietInDb = findGruppeImGebiet(gruppeImGebiet, gruppenImGebietInDb, gruppenImGebietInDbContext, stimmeingabeImporterHelper);

      if (gruppeImGebietInDb == null) {
        stimmeingabeImporterHelper.handleGruppeImGebietInDbNotFound(violations, gruppeImGebiet);
      } else if (stimmeingabeImporterHelper.isGruppeImGebietAufWahlvorschlagPruefen(
          gruppeImGebietInDb)) { // Nicht für Destatis Sondergebiete prüfen (WASDE-2030)
        var stimmenart = stimmeingabe.getStimmenart();
        if (stimmenart.isDirektstimme()) { //ELECT-10897 Stimmen für nicht vorhandene Direktkandidaten abfangen
          if (!gruppenImGebietInDbContext.existsDirektkandidatInDb(gruppeImGebietInDb) && stimmeingabe.hasAnzahlGroesserNull() && gruppeImGebietInDb.getGruppe()
              .isPolitischeGruppe()) {
            violations.addError("stimmeingabe.import.direktkandidate.bei.gruppe.im.gebiete.nicht.vorhanden",
                gruppeImGebietInDb.getGruppe().getName(), gruppeImGebietInDb.getVorgegebenePosition(),
                gebietNummerFormatter.getDarstellung(gruppeImGebietInDb.getGebiet()));
          }
        }
      }

    }
  }

}
