package no.valg.valgnatt.backend;

import java.nio.charset.Charset;
import java.nio.file.Files;

import javax.annotation.Resource;
import no.valg.valgnatt.backend.parser.ParserService;
import no.valg.valgnatt.backend.rapport.MainRapport;
import no.valg.valgnatt.database.FlywayLoader;
import no.valg.valgnatt.database.GrunnlagsdataCache;
import no.valg.valgnatt.database.GrunnlagsdataService;
import no.valg.valgnatt.database.Konstanter;
import no.valg.valgnatt.database.domene.ValgType;
import no.valg.valgnatt.database.domene.ValideringStatus;
import no.valg.valgnatt.database.hibernate.Stemmekrets;
import no.valg.valgnatt.database.hibernate.Stemmeskjema;
import no.valg.valgnatt.database.hibernate.Valgdistrikt;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = BackendSpringConfiguration.class)
@TestExecutionListeners(listeners = {DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class})
@ActiveProfiles("test")
public class BackendIT {

	private static boolean initOk;
	@Resource
	private GrunnlagsdataCache grunnlagsdataCache;
	@Resource
	private GrunnlagsdataService grunnlagsdataService;
	@Resource
	private ParserService parserService;
	@Resource
	private FlywayLoader flywayLoader;
	@Resource
	private MainBackend mainBackend;
	@Resource
	private MainRapport mainRapport;

	@Before
	public void init() throws Exception {
		if (initOk) {
			return;
		}
		// Database som benyttes er angitt av argumentet som benyttes for å kjøre testen, eks: -Dconfiguration=classpath:morten_enhetstest.properties
		// Testen legger opp til å benytte en database satt opp for 2013-valget (ST, SA)
		// Slette alle tabeller i databasen
		grunnlagsdataService.nullstillDatabase();
		// Oppretter alle tabeller i databasen og laster alle data fra CSV'ene inn i databasen
		flywayLoader.initialize();
		// Leser data fra databasen inn i datamodellen
		grunnlagsdataCache.nullstill();
		grunnlagsdataCache.initialize();

		// Kopiert fra klassene MainMottak og StemmeInnsender for å initiere systemet med stemmeskjema før vi kan parse/teste det
		// Det finnes mao. en avhengighet mellom Mottak og Backend som vi ikke tester her (men den testes i Simulatoren), altså at
		// stemmeskjema først må leses inn og skrives til databasen i Mottak, og deretter behandles i Backend (parsing, mandatberegning, osv)
		org.springframework.core.io.Resource[] resources = new PathMatchingResourcePatternResolver().getResources("stemmeskjema/**/*.json");
		for (org.springframework.core.io.Resource resource : resources) {
			Stemmeskjema stemmeskjema = new Stemmeskjema();
			stemmeskjema.setData(new String(Files.readAllBytes(resource.getFile().toPath()), Charset.forName("UTF-8")));
			stemmeskjema.setValideringstatus(ValideringStatus.I);
			stemmeskjema.setValgType(ValgType.ST);   // Hibernate bug-workaround, tillater ikke null for enum, overskrives uansett med riktig verdi senere
			stemmeskjema.setOpptaltstatus(0);
			parserService.lagreStemmeskjema(stemmeskjema);
		}
		initOk = true;
	}

	@Test
	public void getLand1Arg_0() {
		Assert.assertEquals("0", grunnlagsdataCache.getLand(ValgType.ST).getNr());
	}

	@Test
	public void getLand2Arg_0() {
		Assert.assertEquals("0", grunnlagsdataCache.getLand(ValgType.ST).getNr());
	}

	@Test
	public void getFylker_19() {
		Assert.assertEquals(19, grunnlagsdataCache.getFylker(ValgType.ST).size());
	}

	@Test
	public void getFylke1Arg_Akershus() {
		Assert.assertEquals("Akershus", grunnlagsdataCache.getFylke(ValgType.ST, "02").getNavn());
	}

	@Test
	public void getFylke2Arg_Akershus() {
		Assert.assertEquals("Akershus", grunnlagsdataCache.getFylke(ValgType.ST, "02").getNavn());
	}

	@Test
	public void getKommuner_428() {
		Assert.assertEquals(428, grunnlagsdataCache.getKommuner(ValgType.ST).size());
	}

	@Test
	public void getKommune_Enebakk() {
		Assert.assertEquals("Enebakk", grunnlagsdataCache.getKommune(ValgType.ST, "0229").getNavn());
	}

	@Test
	public void getPartiliste_A() {
		Assert.assertEquals("Arbeiderpartiet", grunnlagsdataCache.getPartiliste(ValgType.ST, "A").getPartinavn());
	}

	@Test
	public void getStemmekretser_648() {
		Assert.assertEquals(648, grunnlagsdataCache.getStemmekretser(ValgType.ST).size());
	}

	@Test
	public void getStemmekrest1Arg_HeleKommunen() {
		Assert.assertEquals("Hele kommunen", grunnlagsdataCache.getStemmekrets(ValgType.ST, "0229", Konstanter.DEFAULT_KRETS).getNavn());
	}

	@Test
	public void getValgdistrikter_19() {
		Assert.assertEquals(19, grunnlagsdataCache.getStortingsvalgdistrikter().size());
	}

	@Test
	public void getValgdistrikt_Akershus() {
		Assert.assertEquals("Akershus", grunnlagsdataCache.getValgdistrikt(ValgType.ST, "02").getNavn());
	}

	@Test
	public void testHovedLoop_Les() {
		mainBackend.lesInnNyeStemmeskjema();

		Stemmekrets enebakkSk = grunnlagsdataCache.getStemmekrets(ValgType.ST, "0229", Konstanter.DEFAULT_KRETS);
		Assert.assertEquals(1293, enebakkSk.getParti("A").getStemmer());
		Stemmekrets rælingenSk = grunnlagsdataCache.getStemmekrets(ValgType.ST, "0228", Konstanter.DEFAULT_KRETS);
		Assert.assertEquals(17, (int) rælingenSk.getStgForkastede());

		mainBackend.beregnMandater(true);

		Valgdistrikt akershusVd = grunnlagsdataCache.getValgdistrikt(ValgType.ST, "02");
		Assert.assertEquals(6, akershusVd.getPartiMandater("A").getResultatData().getAntall(ValgType.ST));

		// lager rapporter og sender rapportene til Frontend. Vi sjekker bare at det riktige antall rapporter
		// blir kalkulert, ikke at de blir sendt/mottatt (det blir for komplisert for denne testen - da
		// må man bruke Simulatoren i valg_utils).
		mainBackend.kalkulerRapporter();

		MainRapport.RappCacheEntry rce = mainRapport.getRapporterIdMap().lastEntry().getValue();
		Assert.assertEquals(43, (int) rce.getSeqNr());
	}

}
