/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.sdm.application.service;

import java.io.IOException;
import java.io.PrintWriter;
import java.security.Security;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;

import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.config.shares.exception.SharesException;
import com.scytl.products.ov.sdm.domain.model.ballot.BallotRepository;
import com.scytl.products.ov.sdm.domain.model.ballotbox.BallotBoxRepository;
import com.scytl.products.ov.sdm.domain.model.ballotboxcounting.BallotBoxCountingRepository;
import com.scytl.products.ov.sdm.domain.model.ballottext.BallotTextRepository;
import com.scytl.products.ov.sdm.domain.model.electionevent.ElectionEventRepository;
import com.scytl.products.ov.sdm.domain.model.votingcardset.VotingCardSetRepository;
import com.scytl.products.ov.sdm.infrastructure.JsonConstants;

import mockit.Expectations;
import mockit.Injectable;
import mockit.Tested;
import mockit.integration.junit4.JMockit;

/**
 *
 */
@RunWith(JMockit.class)
public class TallySheetServiceTest {

	@Rule
	public ExpectedException expected = ExpectedException.none();

	@Tested
	private TallySheetService _tallySheetService = new TallySheetService();

	@Injectable
	private ElectionEventRepository _electionEventRepository;

	@Injectable
	private BallotBoxRepository _ballotBoxRepository;

	@Injectable
	private BallotRepository _ballotRepository;

	@Injectable
	private BallotTextRepository _ballotTextRepository;

	@Injectable
	private BallotBoxCountingRepository ballotBoxCountingRepository;
	
	@Injectable
	private VotingCardSetRepository votingCardSetRepository;

	private String electoralAuthorityJSON;

	private String ballotBoxJSON;

	private String ballotText;

	private String countingOutput;

	private String votingCardSetJSON;

	@BeforeClass
	public static void init() {
		Security.addProvider(new BouncyCastleProvider());
	}

	@Ignore
	@Test
	public void createTallySheet() throws ResourceNotFoundException, SharesException, IOException {

		ClassLoader classLoader = getClass().getClassLoader();
		votingCardSetJSON = IOUtils.toString(classLoader.getResource("votingCardSet.json").openStream());
		ballotBoxJSON = IOUtils.toString(classLoader.getResource("ballotBox.json").openStream());
		ballotText = IOUtils.toString(classLoader.getResource("ballotText.json").openStream());
		electoralAuthorityJSON = IOUtils.toString(classLoader.getResource("electoralAuthority.json").openStream());
		countingOutput = IOUtils.toString(classLoader.getResource("counting.json").openStream());

		PrintWriter pw = new PrintWriter(System.out, true);
		String ballotId = "7706441edd1a48828dcfe5357ed55956";
		String ballotBoxId = "a070f8c0dbfd4155aeeeaa3f039f2c7d";
		String electionEventId = "bc80c09dc13642a294754387f601a325";

		new Expectations() {
			{
				Map<String, Object> attributeValueMap = new HashMap<>();
				attributeValueMap.put(JsonConstants.JSON_ATTRIBUTE_NAME_ID, ballotBoxId);
				attributeValueMap.put(JsonConstants.JSON_STRUCTURE_NAME_ELECTION_EVENT_ID, electionEventId);
				ballotBoxCountingRepository.list(attributeValueMap);
				result = countingOutput;

				_electionEventRepository.find(electionEventId);
				result = electoralAuthorityJSON;

				_ballotBoxRepository.find(ballotBoxId);
				result = ballotBoxJSON;

				_ballotBoxRepository.getBallotId(ballotBoxId);
				result = ballotId;

				Map<String,Object> params = new HashMap<>();
				params.put("ballot.id",ballotId);
				_ballotTextRepository.list(params);
				result = ballotText;
				
				Map<String, Object> params2 = new HashMap<>();
				params.put("ballotBox.id", ballotBoxId);
				votingCardSetRepository.list(params2);
				result = votingCardSetJSON;
			}
		};

		_tallySheetService.generate(pw, electionEventId, ballotBoxId);

		pw.close();
	}

	@Ignore
	@Test
	// Counting reuslts with 0 votes for listId1, 20 votes for listId2 and 2 votes for listId3
	public void createTallySheet_for_election() throws ResourceNotFoundException, SharesException, IOException {

		ClassLoader classLoader = getClass().getClassLoader();
		votingCardSetJSON = IOUtils.toString(classLoader.getResource("votingCardSet.json").openStream());
		ballotBoxJSON = IOUtils.toString(classLoader.getResource("ballotBox_election.json").openStream());
		ballotText = IOUtils.toString(classLoader.getResource("ballotText_election.json").openStream());
		electoralAuthorityJSON = IOUtils.toString(classLoader.getResource("electoralAuthority_elec.json").openStream());
		countingOutput = IOUtils.toString(classLoader.getResource("counting_election.json").openStream());

		PrintWriter pw = new PrintWriter(System.out, true);
		String ballotId = "7a644e22fc854b9f97372cc726ed6bb7";
		String ballotBoxId = "4f3d5d82fad24e0fa97e60b47463a77b";
		String electionEventId = "f0077747c4f94508950e2d400e8d57cd";

		new Expectations() {
			{
				Map<String, Object> attributeValueMap = new HashMap<>();
				attributeValueMap.put(JsonConstants.JSON_ATTRIBUTE_NAME_ID, ballotBoxId);
				attributeValueMap.put(JsonConstants.JSON_STRUCTURE_NAME_ELECTION_EVENT_ID, electionEventId);
				ballotBoxCountingRepository.list(attributeValueMap);
				result = countingOutput;

				_electionEventRepository.find(electionEventId);
				result = electoralAuthorityJSON;

				_ballotBoxRepository.find(ballotBoxId);
				result = ballotBoxJSON;

				_ballotBoxRepository.getBallotId(ballotBoxId);
				result = ballotId;

				Map<String,Object> params = new HashMap<>();
				params.put("ballot.id",ballotId);
				_ballotTextRepository.list(params);
				result = ballotText;
				
				Map<String, Object> params2 = new HashMap<>();
				params.put("ballotBox.id", ballotBoxId);
				votingCardSetRepository.list(params2);
				result = votingCardSetJSON;
			}
		};

		_tallySheetService.generate(pw, electionEventId, ballotBoxId);

		pw.close();
	}

	@Ignore
	@Test
	public void createTallySheet_for_election_twoContests() throws ResourceNotFoundException, SharesException, IOException {

		ClassLoader classLoader = getClass().getClassLoader();
		votingCardSetJSON = IOUtils.toString(classLoader.getResource("votingCardSet.json").openStream());
		ballotBoxJSON = IOUtils.toString(classLoader.getResource("ballotBox_election.json").openStream());
		ballotText = IOUtils.toString(classLoader.getResource("ballotText_election.json").openStream());
		electoralAuthorityJSON = IOUtils.toString(classLoader.getResource("electoralAuthority_elec.json").openStream());
		countingOutput = IOUtils.toString(classLoader.getResource("counting_election_twoContests.json").openStream());

		PrintWriter pw = new PrintWriter(System.out, true);
		String ballotId = "7a644e22fc854b9f97372cc726ed6bb7";
		String ballotBoxId = "4f3d5d82fad24e0fa97e60b47463a77b";
		String electionEventId = "f0077747c4f94508950e2d400e8d57cd";

		new Expectations() {
			{
				Map<String, Object> attributeValueMap = new HashMap<>();
				attributeValueMap.put(JsonConstants.JSON_ATTRIBUTE_NAME_ID, ballotBoxId);
				attributeValueMap.put(JsonConstants.JSON_STRUCTURE_NAME_ELECTION_EVENT_ID, electionEventId);
				ballotBoxCountingRepository.list(attributeValueMap);
				result = countingOutput;

				_electionEventRepository.find(electionEventId);
				result = electoralAuthorityJSON;

				_ballotBoxRepository.find(ballotBoxId);
				result = ballotBoxJSON;

				_ballotBoxRepository.getBallotId(ballotBoxId);
				result = ballotId;

				Map<String,Object> params = new HashMap<>();
				params.put("ballot.id",ballotId);
				_ballotTextRepository.list(params);
				result = ballotText;
				
				Map<String, Object> params2 = new HashMap<>();
				params.put("ballotBox.id", ballotBoxId);
				votingCardSetRepository.list(params2);
				result = votingCardSetJSON;
			}
		};

		_tallySheetService.generate(pw, electionEventId, ballotBoxId);

		pw.close();
	}
}
