package no.valg.valgnatt.backend;

import no.valg.valgnatt.database.Konstanter;
import no.valg.valgnatt.database.domene.OpptaltStatus;
import no.valg.valgnatt.database.domene.ValgType;
import no.valg.valgnatt.database.geografi.Bydel;
import no.valg.valgnatt.database.geografi.Fylke;
import no.valg.valgnatt.database.geografi.Kommune;
import no.valg.valgnatt.database.geografi.Land;
import no.valg.valgnatt.database.geografi.Mandater;
import no.valg.valgnatt.database.geografi.PartiMandater;
import no.valg.valgnatt.database.geografi.PartiStemmer;
import no.valg.valgnatt.database.hibernate.Kandidat;
import no.valg.valgnatt.database.hibernate.KandidatId;
import no.valg.valgnatt.database.hibernate.Partiliste;
import no.valg.valgnatt.database.hibernate.PartilisteId;
import no.valg.valgnatt.database.hibernate.Stemmekrets;
import no.valg.valgnatt.database.hibernate.StemmekretsId;
import no.valg.valgnatt.database.hibernate.Valgdistrikt;
import no.valg.valgnatt.database.hibernate.ValgdistriktId;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import static no.valg.valgnatt.database.Konstanter.OSLO_KNR;

/**
 * Tanken er at denne datastrukturen skal lastes en gang, og at ingen tester skal endre innholdet i datastrukturen.
 * Datastrukturen skal være lik den geografiske datastruktren som bygges opp i GrunnlagsdataCache.initialiser(), men
 * svært begrenset i forhold til antall fylker, valgdistrikter, partier, etc. Dette danner dermed et grunnlag
 * for å kjøre diverse tester.
 */
public class GrunnlagsdataMockup {

	private Land land;
	private int valgår;
	private Map<PartilisteId, Partiliste> partilister = new TreeMap<>();


	public void initialiser(ValgType vt, int valgår) {
		land = new Land(vt);
		this.valgår = valgår;
		initialiserPartilister(vt);
		for (int i = 1; i < 21; i = (i == 12 ? (i + 2) : (i + 1))) { // Hopper over fylke 13
			opprettFylke(vt, i, 10, 10);
		}

		if (vt == ValgType.ST || vt == ValgType.FY) {
			land.setValgdistriktForUtjevningsmandaterOgLandsprognose(opprettValgdistrikt(vt, Konstanter.VALGDISTRIKT_NORGE, land.getFylker().size()));
		}
	}

	private void initialiserPartilister(ValgType vt) {
		Partiliste parti;
		parti = initialiserPartiliste(vt, "A", "Arbeiderpartiet", 10001);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "SV", "Sosialistisk Venstreparti", 10002);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "RØDT", "Rødt", 10003);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "SP", "Senterpartiet", 10004);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "KRF", "Kristelig Folkeparti", 10005);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "MDG", "Miljøpartiet De Grønne", 10006);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "V", "Venstre", 10007);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "H", "Høyre", 10008);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "FRP", "Fremskrittspartiet", 10009);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "PP", "Pensjonistpartiet", 20001);
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "BP", "Bondepartiet", 20002); // stiller bare i Akershus/Gjerdrum
		partilister.put(parti.getId(), parti);
		parti = initialiserPartiliste(vt, "BLANKE", " Blanke", 30001);
		partilister.put(parti.getId(), parti);
	}

	private Partiliste initialiserPartiliste(ValgType vt, String partikode, String partinavn, int visningssekvens) {
		Partiliste parti = new Partiliste();
		parti.setId(new PartilisteId(vt, partikode));
		parti.setPartikategori(visningssekvens / 10000); // partikategori 1-3, visningssekvenser settes fra 10000-39999
		parti.setPartinavn(partinavn);
		parti.setVisningssekvens(visningssekvens);
		return parti;
	}

	private void opprettFylke(ValgType vt, int fylkeNr, int antallMandater, int antallKommuner) {

		Valgdistrikt vd = opprettValgdistrikt(vt, String.format("%02d", fylkeNr), antallMandater);

		for (int i = 0; i < antallKommuner; i++) {
			String kommuneNr = String.format("%02d", fylkeNr) + String.format("%02d", i);
			Kommune kommune = new Kommune(kommuneNr, "Kommune" + kommuneNr, true, true);

			Map<String, Bydel> bydeler = null;
			String bydelNr = null;
			if (kommuneNr.equals(OSLO_KNR)) {
				bydelNr = "0";
				bydeler = new HashMap<>();
 				Bydel bydel = new Bydel(bydelNr, "Nordstrand", OSLO_KNR, true, true);
				bydeler.put(bydel.getNr(), bydel);
			}
			
			Stemmekrets sk0000 = opprettStemmekrets(vt, kommune.getNr(), Konstanter.DEFAULT_KRETS, 1500, OpptaltStatus.ALLE_ENDELIG.getStatus(), bydelNr);
			land.add(sk0000, bydeler, kommune.getNavn(), vd, true, true);
			Stemmekrets sk0123 = opprettStemmekrets(vt, kommune.getNr(), "0123", 1500, OpptaltStatus.BARE_VTS_ENDELIG.getStatus(), bydelNr);
			land.add(sk0123, bydeler, kommune.getNavn(), vd, true, true);

			if (i > 4) {
				for (Partiliste partiliste : partilister.values()) {
					int stemmeFaktor = Math.abs((partiliste.getId().getPartikode() + kommune.getNr()).hashCode()) % 10;
					int fhs = partiliste.getPartikategori() == 1 ? stemmeFaktor * 5 : stemmeFaktor;
					int vts = partiliste.getPartikategori() == 1 ? stemmeFaktor * 10 : stemmeFaktor * 2;
					leggTilStemmer(sk0000, OpptaltStatus.ALLE_ENDELIG, partiliste.getId().getPartikode(), fhs, vts, fhs - 1, vts + 3, fhs + 1, vts - 3, true);
					if (i > 7) {
						leggTilStemmer(sk0123, OpptaltStatus.BARE_VTS_ENDELIG, partiliste.getId().getPartikode(), 0, vts, 0, vts + 3, 0, vts - 3, true);
					} else {
						leggTilStemmer(sk0123, OpptaltStatus.INGEN, partiliste.getId().getPartikode(), 0, 0, 0, vts + 3, 0, vts - 3, true);
					}
				}
			}
		}
	}

	private Valgdistrikt opprettValgdistrikt(ValgType vt, String valgdistriktnr, int antallmandater) {
		Valgdistrikt vd = new Valgdistrikt();
		ValgdistriktId valgdistriktId = new ValgdistriktId();
		valgdistriktId.setNr(valgdistriktnr);
		valgdistriktId.setValgType(vt);
		vd.setId(valgdistriktId);
		vd.setAntallmandater(antallmandater);
		for (Partiliste p : partilister.values()) {
			vd.addPartiMandater(new PartiMandater(p.getId().getPartikode(), p.getPartinavn(), "" + p.getPartikategori(), "" + p.getVisningssekvens(), true));
		}
		return vd;
	}

	private Stemmekrets opprettStemmekrets(ValgType vt, String kommnr, String kretsnr, int stemmeberettigede, int opptaltstatusMax, String bydelnr) {
		StemmekretsId stemmekretsId = new StemmekretsId();
		stemmekretsId.setValgtype(vt);
		stemmekretsId.setKommnr(kommnr);
		stemmekretsId.setKretsnr(kretsnr);
		Stemmekrets stemmekrets = new Stemmekrets();
		stemmekrets.setId(stemmekretsId);
		stemmekrets.setStemmeberettigede(stemmeberettigede);
		stemmekrets.setOpptaltStatusMax(opptaltstatusMax);
		stemmekrets.setBydelnr(bydelnr);
		return stemmekrets;
	}

	private void leggTilStemmer(Stemmekrets stemmekrets, OpptaltStatus os, String partikode, int fhs, int vts, int sfhs, int svts, int nsfhs, int nsvts, boolean stillerliste) {
		stemmekrets.setOpptaltStatus(os.getStatus());
		Partiliste parti = partilister.get(new PartilisteId(stemmekrets.getValgType(), partikode));
		PartiStemmer partiStemmer = new PartiStemmer(parti.getId().getPartikode(), parti.getPartinavn(), "" + parti.getPartikategori(), "" + parti.getVisningssekvens(), stillerliste);
		partiStemmer.setFhs(fhs);
		partiStemmer.setVts(vts);
		partiStemmer.setSisteFhs(sfhs);
		partiStemmer.setSisteVts(svts);
		partiStemmer.setNestsisteFhs(nsfhs);
		partiStemmer.setNestsisteVts(nsvts);
		stemmekrets.setPartistemmer(partiStemmer);
	}

	public void leggTilMandaterOgKandidater() {
		for (Fylke fylke : getLand().getFylker().values()) {
			for (Partiliste partiliste : partilister.values()) {
				PartiMandater pm = new PartiMandater(partiliste.getId().getPartikode(), partiliste.getPartinavn(), "" + partiliste.getPartikategori(), "" + partiliste.getVisningssekvens(), true);
				pm.setHarStartetOpptelling(true);
				pm.getResultatData().setStemmer(1000);
				pm.getResultatData().setDistriktsmandater(new Mandater(1, 1, 1));
				pm.getResultatData().setUtjevningmandater(new Mandater(1, 1, 1));
				for (int i = 0; i < 10; i++) {
					Kandidat k = new Kandidat();
					KandidatId kId = new KandidatId(valgår, i + 1);
					k.setId(kId);
					k.setFodselsdato("1973-01-0" + (i + 1));
					k.setKjonn("M");
					k.setNavn("Ola Nordmann " + i);
					pm.addKandidat(k);
				}
				fylke.getValgdistrikt().addPartiMandater(pm);
			}
		}
		for (Partiliste partiliste : partilister.values()) {
			PartiMandater pm = new PartiMandater(partiliste.getId().getPartikode(), partiliste.getPartinavn(), "" + partiliste.getPartikategori(),"" + partiliste.getVisningssekvens(), true);
			pm.setHarStartetOpptelling(true);
			pm.getResultatData().setStemmer(1000);
			pm.getResultatData().setUtjevningmandater(new Mandater(1, 1, 1));
			getLand().getValgdistrikt().addPartiMandater(pm);
		}
	}

	public Land getLand() {
		return land;
	}
}
