/*
 * 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 static org.mockito.Matchers.anyMapOf;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.OperatorCreationException;

import mockit.Expectations;

import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.sdm.domain.model.ballot.BallotRepository;
import com.scytl.products.ov.sdm.domain.model.ballottext.BallotTextRepository;
import com.scytl.products.ov.sdm.domain.model.status.Status;
import com.scytl.products.ov.sdm.infrastructure.service.ConfigurationEntityStatusService;

/**
 *
 */
@RunWith(MockitoJUnitRunner.class)
public class BallotServiceTest {

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

	@InjectMocks
	private BallotService ballotService = new BallotService();

	@Mock
	private ConfigurationEntityStatusService statusServiceMock;

	@Mock
	private BallotRepository ballotRepositoryMock;

	@Mock
	private BallotTextRepository ballotTextRepositoryMock;

	// this is just part of a json ballot!
	private String ballotLOCKED = "{\"result\": [{\"id\": \"8365b61d3f194c11bbd03e421462b6ad\", "
		+ "\"defaultTitle\": \"Ballot Title\", \"defaultDescription\": \"Ballot Description\", \"alias\": \"Ballot Alias\",  "
		+ "\"electionEvent\": { \"id\": \"db033b3f729c45719db8aba15d24043c\" }, \"status\": \"LOCKED\"}]}";

	// this is just part of a json ballot!
	private String ballotAlreadySIGNED = "{\"result\": [{\"id\": \"8365b61d3f194c11bbd03e421462b6ad\", " +
		"\"defaultTitle\": \"Ballot Title\", \"defaultDescription\": \"Ballot Description\", \"alias\": \"Ballot " +
		"Alias\", \"electionEvent\": { \"id\": \"db033b3f729c45719db8aba15d24043c\" }, \"status\": \"SIGNED\"}]}";

	// this is just part of a json ballot!
	private String ballotWithoutStatus = "{\"result\": [{\"id\": \"8365b61d3f194c11bbd03e421462b6ad\", "
		+ "\"defaultTitle\": \"Ballot Title\", \"defaultDescription\": \"Ballot Description\", \"alias\": \"Ballot Alias\",  "
		+ "\"electionEvent\": { \"id\": \"db033b3f729c45719db8aba15d24043c\" }}]}";

	private String ballotText = "{\"result\": [{\"id\": \"8365b61d3f194c11bbd03e421462b6aden_GB\", \"ballot\":{  \n" +
		"            \"id\":\"2b738a1093674f3f9df9e2f125e28bd6\"\n" + "         },\n" + "         \"locale\":\"en_GB\",\n" +
		"         \"texts\":{  \n" + "            \"4b36f7ebed1f41249e8540d0b60e21a1\":{  \n" +
		"               \"title\":\"Proportional Votation 18/12/2015\",\n" +
		"               \"description\":\"Proportional Votation 18/12/2015\",\n" +
		"               \"howToVote\":\"Choose a Party List\",\n" + "               \"listColumn1\":\"ID\",\n" +
		"               \"listColumn2\":\"Name\",\n" + "               \"listColumn3\":\"More info\",\n" +
		"               \"candidateColumn1\":\"ID\",\n" + "               \"candidateColumn2\":\"Name\",\n" +
		"               \"candidateColumn3\":\"Attribute 3\",\n" +
		"               \"candidateColumn4\":\"Attribute 4\",\n" + "               \"candidateColumn5\":\"Attribute 5\"\n" +
		"            },\n" + "            \"6e3b0f45125b412ba475da9572b5f6cc\":{  \n" +
		"               \"text\":\"Maggie Greene\"\n" + "            },\n" +
		"            \"4e81c4b471cd471e9bbda7951d1c983c\":{  \n" +
		"               \"candidateColumn2\":\"Jimmey Kimmel\",\n" + "               \"candidateColumn3\":\"Attrib 3\",\n" +
		"               \"candidateColumn4\":\"Attrib 4\",\n" + "               \"candidateColumn5\":\"Attrib 5\"\n" +
		"            },\n" + "            \"f07066a88d714d56be8ad042b0088731\":{  \n" +
		"               \"listColumn2\":\"Green Party\",\n" + "               \"listColumn3\":\"Information Available\"\n" +
		"            },\n" + "            \"295588646bc3444e9a164772c6df4961\":{  \n" +
		"               \"text\":\"Choose 1 of the following Candidates\"\n" + "            },\n" +
		"            \"79f65edca2ea4ca09418087a724a48cb\":{  \n" +
		"               \"candidateColumn2\":\"Beth Greene\",\n" + "               \"candidateColumn3\":\"Attrib 3\",\n" +
		"               \"candidateColumn4\":\"Attrib 4\",\n" + "               \"candidateColumn5\":\"Attrib 5\"\n" +
		"            },\n" + "            \"2bf79af73c2c4736810bdcee75327dfd\":{  \n" +
		"               \"text\":\"Hershel Greene\"\n" + "            },\n" +
		"            \"5a8f6032029d422091066289ca4c5873\":{  \n" + "               \"text\":\"Blank\"\n" +
		"            },\n" + "            \"121dd9b2f6da4db08a2bae14a5ab1575\":{  \n" +
		"               \"text\":\"Choose 1 of the following Candidates (Not Mandatory)\"\n" + "            },\n" +
		"            \"8588552235a845b78d20d34e5ebd003a\":{  \n" + "               \"text\":\"Blank\"\n" +
		"            },\n" + "            \"2b738a1093674f3f9df9e2f125e28bd6\":{  \n" +
		"               \"title\":\"Mixed Ballot 18/12/2015\",\n" +
		"               \"description\":\"Mixed Ballot 18/12/2015\"\n" + "            },\n" +
		"            \"55b64aaf621a4eb9ba5413d46e10ad11\":{  \n" + "               \"text\":\"Lori Grimes\"\n" +
		"            },\n" + "            \"a2e3efce959e4fbea4366a773b9d1196\":{  \n" +
		"               \"candidateColumn2\":\"JimmeyO'Neal\",\n" + "               \"candidateColumn3\":\"Attrib 3\",\n" +
		"               \"candidateColumn4\":\"Attrib 4\",\n" + "               \"candidateColumn5\":\"Attrib 5\"\n" +
		"            },\n" + "            \"9a536a836d64404b8b0304a81fd16e9a\":{  \n" +
		"               \"listColumn2\":\"Orange Party\",\n" +
		"               \"listColumn3\":\"Information Available\"\n" + "            },\n" +
		"            \"685f85dc5bfc4d0da76edbde42d5b2d0\":{  \n" +
		"               \"candidateColumn2\":\"Morgan Jones\",\n" + "               \"candidateColumn3\":\"Attrib 3\",\n" +
		"               \"candidateColumn4\":\"Attrib 4\",\n" + "               \"candidateColumn5\":\"Attrib 5\"\n" +
		"            },\n" + "            \"9284e8b193b741a6b9d2050782a163e9\":{  \n" +
		"               \"text\":\"Daryl Dixon\"\n" + "            },\n" +
		"            \"979dc2814a52450fb7dd1e95a805e368\":{  \n" +
		"               \"candidateColumn2\":\"Graham Norton\",\n" + "               \"candidateColumn3\":\"Attrib 3\",\n" +
		"               \"candidateColumn4\":\"Attrib 4\",\n" + "               \"candidateColumn5\":\"Attrib 5\"\n" +
		"            },\n" + "            \"8f79d0b7ce134640a6fa3383fe7ece7c\":{  \n" +
		"               \"title\":\"Direct Votation 18/12/2015\",\n" +
		"               \"description\":\"Direct Votation 18/12/2015\"\n" + "            },\n" +
		"            \"906fd2e1aaf449c5a42b316f6dc7b817\":{  \n" + "               \"candidateColumn2\":\"Andrea\",\n" +
		"               \"candidateColumn3\":\"Attrib 3\",\n" + "               \"candidateColumn4\":\"Attrib 4\",\n" +
		"               \"candidateColumn5\":\"Attrib 5\"\n" + "            },\n" +
		"            \"1b63c6549825419db8f52944037eece0\":{  \n" + "               \"listColumn2\":\"Blue Party\",\n" +
		"               \"listColumn3\":\"Information Available\"\n" + "            },\n" +
		"            \"c321c9e0d75c45089fd251672637182b\":{  \n" + "               \"candidateColumn2\":\"Michonne\",\n" +
		"               \"candidateColumn3\":\"Attrib 3\",\n" + "               \"candidateColumn4\":\"Attrib 4\",\n" +
		"               \"candidateColumn5\":\"Attrib 5\"\n" + "            }\n" + "         }\n" + "      }]}";
	
	@BeforeClass
    public static void init() {
        Security.addProvider(new BouncyCastleProvider());
	}
	
	@Test
	public void sign() throws ResourceNotFoundException, GeneralCryptoLibException {

		ballotService.init();

		String electionEventId = "db033b3f729c45719db8aba15d24043c";
		String ballotId = "8365b61d3f194c11bbd03e421462b6ad";
		String ballotTextId = "8365b61d3f194c11bbd03e421462b6aden_GB";

		when(ballotRepositoryMock.list(anyMapOf(String.class, Object.class))).thenReturn(ballotLOCKED);
		when(ballotTextRepositoryMock.list(anyMapOf(String.class, Object.class))).thenReturn(ballotText);
		when(statusServiceMock.update(Status.SIGNED.name(), ballotId, ballotRepositoryMock)).thenReturn(ballotId);

		new Expectations() {
			{
				ballotRepositoryMock.updateSignedBallot(ballotId, "");
				ballotTextRepositoryMock.updateSignedBallotText(ballotTextId, "");
			}
		};

		ballotService.sign(electionEventId, ballotId, SigningTestData.PRIVATE_KEY_PEM);
	}

	@Test
	public void signFails() throws ResourceNotFoundException, GeneralCryptoLibException {

		ballotService.init();

		String electionEventId = "db033b3f729c45719db8aba15d24043c";
		String ballotId = "8365b61d3f194c11bbd03e421462b6ad";

		when(ballotRepositoryMock.list(anyMapOf(String.class, Object.class)))
			.thenThrow(ResourceNotFoundException.class);

		expectedException.expect(ResourceNotFoundException.class);
		ballotService.sign(electionEventId, ballotId, SigningTestData.PRIVATE_KEY_PEM);
	}

	@Test
	public void signEmptyJsonBallot() throws ResourceNotFoundException, GeneralCryptoLibException {

		ballotService.init();
		String electionEventId = "db033b3f729c45719db8aba15d24043c";
		String ballotId = "8365b61d3f194c11bbd03e421462b6ad";

		when(ballotRepositoryMock.list(anyMapOf(String.class, Object.class))).thenReturn("{}");

		expectedException.expect(ResourceNotFoundException.class);
		ballotService.sign(electionEventId, ballotId, SigningTestData.PRIVATE_KEY_PEM);
	}

	@Test
	public void signEmptyStringBallot() throws ResourceNotFoundException, GeneralCryptoLibException {
		String electionEventId = "db033b3f729c45719db8aba15d24043c";
		String ballotId = "8365b61d3f194c11bbd03e421462b6ad";

		when(ballotRepositoryMock.list(anyMapOf(String.class, Object.class))).thenReturn("");

		expectedException.expect(ResourceNotFoundException.class);

		ballotService.sign(electionEventId, ballotId, SigningTestData.PRIVATE_KEY_PEM);
	}

	@Test
	public void signNullBallot() throws ResourceNotFoundException, GeneralCryptoLibException {
		String electionEventId = "db033b3f729c45719db8aba15d24043c";
		String ballotId = "8365b61d3f194c11bbd03e421462b6ad";

		when(ballotRepositoryMock.list(anyMapOf(String.class, Object.class))).thenReturn(null);

		expectedException.expect(ResourceNotFoundException.class);

		ballotService.sign(electionEventId, ballotId, SigningTestData.PRIVATE_KEY_PEM);
	}
}
