/*
 * 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.commons.verify;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.asymmetric.service.AsymmetricService;
import com.scytl.cryptolib.primitives.primes.utils.PemUtils;
import com.scytl.products.ov.commons.sign.CSVSigner;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.Security;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;

public class CSVVerifierTest {

	private static CSVVerifier sut;

	private static Path sourceCSVNotSigned = Paths.get("src/test/resources/example.csv");

	private static Path sourceCSVWithWrongSignature = Paths.get("src/test/resources/signedExampleWrongSignature.csv");

	private static Path sourceCSVWithModifiedContent = Paths.get("src/test/resources/signedExampleModifiedContent.csv");

	private static Path outputCSV = Paths.get("target/signedExample.csv");

	private static Path outputCSVNotSigned = Paths.get("target/exampleNotSigned.csv");

	private static Path outputCSVWithWrongSignature = Paths.get("target/signedExampleWrongSignature.csv");

	private static Path outputCSVWithModifiedContent = Paths.get("target/signedExampleModifiedContent.csv");

	private static String publicKeyPEM = "-----BEGIN PUBLIC KEY-----\n" +
		"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvhIIHMFn8y4gyR3Gb0H5\n" +
		"a8ZJzgawlzqttp6Zq8Ri2lBSdK6M0YrRc9W8HH2EwEOYTNW7Y5Jmvn0a2PRipCtu\n" +
		"R1UEqTeSUHRBSXcxPm4oyHVnChQbshvpHYfNJA6xzC04S1PibrwC1TnIyMb/w30X\n" +
		"zQmwb1FmRlanZz5omq9NpDK7Lg3kLAZQogqTvhmwhTPZxElFYJ38PutZEDWj+OPL\n" +
		"XMcLo2WiCnW/uLsMca0uxUci/q/axRIrzmdb2FSkrKHTgrE9LKiU/SdYFaRyzEce\n" +
		"je/Sd5MMiBGoQK2iy8j/rHKmktbRcWyp8KhqbQ7EZttsIwFnyuqpIA1x0aRAUOj6\n" + "mQIDAQAB\n" + "-----END PUBLIC KEY-----";

	private static PublicKey publicKey;

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

	@BeforeClass
	public static void setUp() throws GeneralCryptoLibException, IOException {

        Security.addProvider(new BouncyCastleProvider());
        
		sut = new CSVVerifier();
		publicKey = PemUtils.publicKeyFromPem(publicKeyPEM);

		Files.copy(sourceCSVNotSigned, outputCSV, StandardCopyOption.REPLACE_EXISTING);
		Files.copy(sourceCSVNotSigned, outputCSVNotSigned, StandardCopyOption.REPLACE_EXISTING);
		Files.copy(sourceCSVWithWrongSignature, outputCSVWithWrongSignature, StandardCopyOption.REPLACE_EXISTING);
		Files.copy(sourceCSVWithModifiedContent, outputCSVWithModifiedContent, StandardCopyOption.REPLACE_EXISTING);
	}

	@Test
	public void verify_a_given_signed_csv_file() throws IOException, GeneralCryptoLibException {
	    CSVSigner signer = new CSVSigner();
        AsymmetricService asymmetricService = new AsymmetricService();
        KeyPair keyPairForSigning = asymmetricService.getKeyPairForSigning();
        int originalNumberOfLines = Files.readAllLines(outputCSV).size();
        signer.sign(keyPairForSigning.getPrivate(), outputCSV);

        int numberLines = Files.readAllLines(outputCSV).size();
		boolean verified = sut.verify(keyPairForSigning.getPublic(), outputCSV);

        assertThat(Files.readAllLines(outputCSV).size(), is(numberLines - 2));
        assertThat(originalNumberOfLines, is(numberLines - 2));
		assertThat(verified, is(true));
	}

	@Test
	public void not_verify_a_given_signed_csv_file_with_a_modified_signature()
			throws IOException, GeneralCryptoLibException {

		boolean verified = sut.verify(publicKey, outputCSVWithWrongSignature);

		assertThat(verified, is(false));
	}

	@Test
	public void not_verify_a_given_signed_csv_file_with_a_modified_content() throws IOException, GeneralCryptoLibException {

		boolean verified = sut.verify(publicKey, outputCSVWithModifiedContent);

		assertThat(verified, is(false));
	}

	@Test
	public void throw_exception_when_non_existing_file_is_passed() throws IOException, GeneralCryptoLibException {

		expectedException.expect(IOException.class);
		sut.verify(publicKey, Paths.get("blabla.csv"));
	}

	@Test
	public void throw_exception_when_null_file_path_is_passed() throws IOException, GeneralCryptoLibException {

		expectedException.expect(IOException.class);
		sut.verify(publicKey, null);
	}

	@Test
	public void not_verify_a_file_without_signature() throws IOException, GeneralCryptoLibException {

		boolean verified = sut.verify(publicKey, outputCSVNotSigned);
		assertThat(verified, is(false));
	}

}
