package no.valg.valgnatt.backend.mandatberegning.prognose;

import java.math.BigDecimal;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

import no.valg.valgnatt.backend.mandatberegning.domene.KommuneKrets;
import no.valg.valgnatt.backend.mandatberegning.domene.KommuneKretsParti;
import no.valg.valgnatt.backend.mandatberegning.domene.Kvotient;

/**
 * Mange forholdsvis enkle kalkulasjoner/transformasjoner
 */
public class Diverse {

	private Diverse() {
	}

	static Map<String, Integer> aggregerStemmerPrParti(Map<KommuneKretsParti, Integer> stemmerPrKommuneKretsParti) {
		return stemmerPrKommuneKretsParti.entrySet().stream().
				collect(Collectors.groupingBy(entry -> entry.getKey().getPartikode(), Collectors.summingInt(Map.Entry::getValue)));
	}

	public static Map<KommuneKrets, Integer> aggregerStemmerPrKrets(Map<KommuneKretsParti, Integer> stemmerPrKommuneKretsParti) {
		return stemmerPrKommuneKretsParti.entrySet().stream().
				collect(Collectors.groupingBy(entry -> entry.getKey().getKommuneKrets(), Collectors.summingInt(Map.Entry::getValue)));
	}

	static Set<KommuneKrets> finnKretser(Map<KommuneKretsParti, Integer> stemmerPrKommuneKretsParti) {
		return stemmerPrKommuneKretsParti.keySet().stream().collect(Collectors.groupingBy(KommuneKretsParti::getKommuneKrets)).keySet();
	}

	static Set<String> finnKommnr(Map<KommuneKretsParti, Integer> stemmerPrKommuneKretsParti) {
		return stemmerPrKommuneKretsParti.keySet().stream().collect(Collectors.groupingBy(KommuneKretsParti::getKommNr)).keySet();
	}

	static Map<KommuneKretsParti, Integer> filtrerKommuner(Map<KommuneKretsParti, Integer> map, Set<String> kommuner) {
		return map.entrySet().stream().
				filter(e -> kommuner.contains(e.getKey().getKommNr())).
				collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, TreeMap::new));
	}

	static TreeMap<KommuneKretsParti, Integer> filtrerKretser(Map<KommuneKretsParti, Integer> map, Set<KommuneKrets> kretser) {
		return map.entrySet().stream().
				filter(e -> kretser.contains(e.getKey().getKommuneKrets())).
				collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, TreeMap::new));
	}

	static TreeMap<String, Kvotient> andeler(Map<String, Integer> stemmerPrParti) {
		int alleStemmer = stemmerPrParti.values().stream().mapToInt(i -> i).sum();
		return stemmerPrParti.entrySet().stream().
				collect(Collectors.toMap(Map.Entry::getKey, e -> alleStemmer == 0 ? new Kvotient(BigDecimal.ZERO) : new Kvotient(e.getValue(), alleStemmer), (a, b) -> a,
						TreeMap::new));
	}

	static TreeMap<KommuneKretsParti, Kvotient> andelerForBetaPartier(Map<KommuneKretsParti, Integer> stemmerPrKommuneKretsParti, Set<String> betaPartier) {
		Map<KommuneKrets, Integer> stemmerPrKommuneKrets = stemmerPrKommuneKretsParti.entrySet().stream().
				collect(Collectors.groupingBy(e -> e.getKey().getKommuneKrets(), Collectors.summingInt(Map.Entry::getValue)));
		return stemmerPrKommuneKretsParti.entrySet().stream().
				filter(e -> betaPartier.contains(e.getKey().getPartikode())).
				filter(e -> stemmerPrKommuneKrets.get(e.getKey().getKommuneKrets()) > 0).
				collect(Collectors.toMap(Map.Entry::getKey, e -> new Kvotient(e.getValue(), stemmerPrKommuneKrets.get(e.getKey().getKommuneKrets())), (a, b) -> a,
						TreeMap::new));
	}

	static TreeMap<String, Kvotient> fjernNegativeAndeler(Map<String, Kvotient> kvotienterPrParti) {
		return kvotienterPrParti.entrySet().stream().
				collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getKvotient().compareTo(BigDecimal.ZERO) < 0 ? new Kvotient(0) : e.getValue(), (a, b) -> a,
						TreeMap::new));
	}

	static TreeMap<String, Kvotient> fordelAndelerPåHundreProsent(Map<String, Kvotient> kvotienterPrParti) {
		TreeMap<String, Kvotient> result = new TreeMap<>();
		BigDecimal kvotientSum = kvotienterPrParti.values().stream().map(Kvotient::getKvotient).reduce(BigDecimal.ZERO, BigDecimal::add);
		for (String partikode : kvotienterPrParti.keySet()) {
			result.put(partikode, kvotienterPrParti.get(partikode).divide(kvotientSum));
		}
		return result;
	}


}
