/*
 * 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.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Set;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.ElGamalPrivateKey;
import com.scytl.cryptolib.elgamal.bean.ElGamalPublicKey;
import com.scytl.cryptolib.primitives.primes.utils.PemUtils;
import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.oscore.logging.core.provider.TransactionInfoProvider;
import com.scytl.products.ov.commons.beans.AuthenticationContextData;
import com.scytl.products.ov.commons.beans.AuthenticationVoterData;
import com.scytl.products.ov.commons.beans.ElectionInformationContents;
import com.scytl.products.ov.commons.beans.ElectoralAuthority;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.path.PathResolver;
import com.scytl.products.ov.commons.path.PrefixPathResolver;
import com.scytl.products.ov.commons.verify.JSONVerifier;
import com.scytl.products.ov.config.shares.exception.SharesException;
import com.scytl.products.ov.config.shares.handler.CreateSharesHandler;
import com.scytl.products.ov.config.shares.handler.StatelessReadSharesHandler;
import com.scytl.products.ov.config.shares.keys.elgamal.ElGamalPrivateKeyAdapter;
import com.scytl.products.ov.constants.Constants;
import com.scytl.products.ov.sdm.application.config.SmartCardConfig;
import com.scytl.products.ov.sdm.application.patch.CreateEBKeysSerializer;
import com.scytl.products.ov.sdm.domain.common.SignedObject;
import com.scytl.products.ov.sdm.domain.model.EntityRepository;
import com.scytl.products.ov.sdm.domain.model.administrationauthority.ActivateOutputData;
import com.scytl.products.ov.sdm.domain.model.ballotbox.BallotBoxRepository;
import com.scytl.products.ov.sdm.domain.model.electionevent.ElectionEventRepository;
import com.scytl.products.ov.sdm.domain.model.electoralauthority.ElectoralAuthorityRepository;
import com.scytl.products.ov.sdm.domain.model.status.SynchronizeStatus;
import com.scytl.products.ov.sdm.domain.service.ConfigConstants;
import com.scytl.products.ov.sdm.domain.service.impl.ElectoralAuthorityDataGeneratorServiceImpl;
import com.scytl.products.ov.sdm.infrastructure.service.ConfigurationEntityStatusService;
import com.scytl.products.ov.utils.ConfigObjectMapper;

import mockit.Deencapsulation;
import mockit.Expectations;
import mockit.Injectable;
import mockit.Mock;
import mockit.MockUp;
import mockit.Mocked;
import mockit.integration.junit4.JMockit;

@Ignore
@RunWith(JMockit.class)
public class ElectoralAuthorityServiceTest {

    public static final String serializedElectoralAuthorityPublicKey =
        "eyJwdWJsaWNLZXkiOnsienBTdWJncm91cCI6eyJnIjoiQWc9PSIsInEiOiJRTmI1aG5GbmtUNTlFMTNyMHhBeHdMR056QVNqRy9uOUVEdWM4c0lZV0VjWFBRc05wZ1BnS2hsUnNxYmp4TEFDZUhNa1EzeWJhVC9yc3B1Nis5MlM3QXhHSVlrMW42T3BXL1JnT2JnRmNIcXFyTUd2aXBmbGlla3J6L0ZaWjIxNXpaUlRlajdQcDdGTmZmVDR1RytlYmM0NDdyb21oZ01rVXJidGViM2VrWlhBZ2RZTUpjQ0RZSk5ZN0tqRkx4OWo2YW14VERZNS8zZW1yN1NpYndwOHlSemttMkRRLzBrSzRQek5nQTFiS3lEK2puYmdCcmhEdlVvcEJrWG4vSW1WVW1pMjBlNXl0cjhXR2VDek9aRTBtdFYzNTF4cjVURlJ4UVo1MU1xUmJDK0ovdndscEpQNE5TU05tYUxyc2JtMnFobTNUZjB4VE5XZVVOcUsrMGdmZ3c9PSIsInAiOiJBSUd0OHd6aXp5SjgraWE3MTZZZ1k0RmpHNWdKUmpmeitpQjNPZVdFTUxDT0xub1dHMHdId0ZReW8yVk54NGxnQlBEbVNJYjVOdEovMTJVM2RmZTdKZGdZakVNU2F6OUhVcmZvd0hOd0N1RDFWVm1EWHhVdnl4UFNWNS9pc3M3YTg1c29wdlI5bjA5aW12dnA4WERmUE51Y2NkMTBUUXdHU0tWdDJ2Tjd2U01yZ1FPc0dFdUJCc0Vtc2RsUmlsNCt4OU5UWXBoc2MvN3ZUVjlwUk40VStaSTV5VGJCb2Y2U0ZjSDVtd0FhdGxaQi9SenR3QTF3aDNxVVVneUx6L2tUS3FUUmJhUGM1VzErTERQQlpuTWlhVFdxNzg2NDE4cGlvNG9NODZtVkl0aGZFLzM0UzBrbjhHcEpHek5GMTJOemJWUXpicHY2WXBtclBLRzFGZmFRUHdjPSJ9LCJlbGVtZW50cyI6WyJXS1BqK2MvN0VRYjV3Y1VGN0EvZStsZy9SdFRXQjMvTEQzUTRMd2Zmc2dyenN1ZlZQZU4wM1hBY1Rta1psbXNTMVpkdjZ3dzZBQVpvbkRwb1ZudkxNbUtScy9ZNUQxOTA3dk10dGNucU9KTDh3dU5NSWtTNWNVR0xGRWhsUEUwNjZBN0VQcHpiYnh1a0srOGJBdWRlbG9UWGJVRzB2OXNXY2p6STdoU3ZHc3RRZlBBVzZ5SytRYlp6dElLK2Fra2pNdm9ZY1NwRGtMRjBqT1FCZEU4a0xSejc0ODljTDU1MU9nTGxjWEtOWWZHRFJTSVYyaGxMSW5xRXhFbU1vbVAvWWUxMUo3QXAycFdWWWJMTWpHeWJXaS9HYUxMVi9aaFlUYzlHZ2N1cExJY3BMYUZQaXh0L1Q5anNPSzUxZkZOWSthOVRkc3dkVHNRWUFXczJBSmFEa1E9PSJdfX0=";

    public static final String serializedElectoralAuthorityPublicKeyDecoded =
        "{\"publicKey\":{\"zpSubgroup\":{\"p\":\"AIGt8wzizyJ8+ia716YgY4FjG5gJRjfz+iB3OeWEMLCOLnoWG0wHwFQyo2VNx4lgBPDmSIb5NtJ/12U3dfe7JdgYjEMSaz9HUrfowHNwCuD1VVmDXxUvyxPSV5/iss7a85sopvR9n09imvvp8XDfPNuccd10TQwGSKVt2vN7vSMrgQOsGEuBBsEmsdlRil4+x9NTYphsc/7vTV9pRN4U+ZI5yTbBof6SFcH5mwAatlZB/RztwA1wh3qUUgyLz/kTKqTRbaPc5W1+LDPBZnMiaTWq786418pio4oM86mVIthfE/34S0kn8GpJGzNF12NzbVQzbpv6YpmrPKG1FfaQPwc=\",\"q\":\"QNb5hnFnkT59E13r0xAxwLGNzASjG/n9EDuc8sIYWEcXPQsNpgPgKhlRsqbjxLACeHMkQ3ybaT/rspu6+92S7AxGIYk1n6OpW/RgObgFcHqqrMGvipfliekrz/FZZ215zZRTej7Pp7FNffT4uG+ebc447romhgMkUrbteb3ekZXAgdYMJcCDYJNY7KjFLx9j6amxTDY5/3emr7Sibwp8yRzkm2DQ/0kK4PzNgA1bKyD+jnbgBrhDvUopBkXn/ImVUmi20e5ytr8WGeCzOZE0mtV351xr5TFRxQZ51MqRbC+J/vwlpJP4NSSNmaLrsbm2qhm3Tf0xTNWeUNqK+0gfgw==\",\"g\":\"Ag==\"},\"elements\":[\"WKPj+c/7EQb5wcUF7A/e+lg/RtTWB3/LD3Q4LwffsgrzsufVPeN03XAcTmkZlmsS1Zdv6ww6AAZonDpoVnvLMmKRs/Y5D1907vMttcnqOJL8wuNMIkS5cUGLFEhlPE066A7EPpzbbxukK+8bAudeloTXbUG0v9sWcjzI7hSvGstQfPAW6yK+QbZztIK+akkjMvoYcSpDkLF0jOQBdE8kLRz7489cL551OgLlcXKNYfGDRSIV2hlLInqExEmMomP/Ye11J7Ap2pWVYbLMjGybWi/GaLLV/ZhYTc9GgcupLIcpLaFPixt/T9jsOK51fFNY+a9TdswdTsQYAWs2AJaDkQ==\"]}}";

    public static final String serializedElectoralAuthorityPrivateKey =
        "eyJwcml2YXRlS2V5Ijp7InpwU3ViZ3JvdXAiOnsicCI6IkFJR3Q4d3ppenlKOCtpYTcxNllnWTRGakc1Z0pSamZ6K2lCM09lV0VNTENPTG5vV0cwd0h3RlF5bzJWTng0bGdCUERtU0liNU50Si8xMlUzZGZlN0pkZ1lqRU1TYXo5SFVyZm93SE53Q3VEMVZWbURYeFV2eXhQU1Y1L2lzczdhODVzb3B2UjluMDlpbXZ2cDhYRGZQTnVjY2QxMFRRd0dTS1Z0MnZON3ZTTXJnUU9zR0V1QkJzRW1zZGxSaWw0K3g5TlRZcGhzYy83dlRWOXBSTjRVK1pJNXlUYkJvZjZTRmNINW13QWF0bFpCL1J6dHdBMXdoM3FVVWd5THova1RLcVRSYmFQYzVXMStMRFBCWm5NaWFUV3E3ODY0MThwaW80b004Nm1WSXRoZkUvMzRTMGtuOEdwSkd6TkYxMk56YlZRemJwdjZZcG1yUEtHMUZmYVFQd2M9IiwicSI6IlFOYjVobkZua1Q1OUUxM3IweEF4d0xHTnpBU2pHL245RUR1YzhzSVlXRWNYUFFzTnBnUGdLaGxSc3FianhMQUNlSE1rUTN5YmFUL3JzcHU2KzkyUzdBeEdJWWsxbjZPcFcvUmdPYmdGY0hxcXJNR3ZpcGZsaWVrcnovRlpaMjE1elpSVGVqN1BwN0ZOZmZUNHVHK2ViYzQ0N3JvbWhnTWtVcmJ0ZWIzZWtaWEFnZFlNSmNDRFlKTlk3S2pGTHg5ajZhbXhURFk1LzNlbXI3U2lid3A4eVJ6a20yRFEvMGtLNFB6TmdBMWJLeUQram5iZ0JyaER2VW9wQmtYbi9JbVZVbWkyMGU1eXRyOFdHZUN6T1pFMG10VjM1MXhyNVRGUnhRWjUxTXFSYkMrSi92d2xwSlA0TlNTTm1hTHJzYm0ycWhtM1RmMHhUTldlVU5xSyswZ2Zndz09IiwiZyI6IkFnPT0ifSwiZXhwb25lbnRzIjpbIkFBPT0iXX19";

    public static final String serializedElectoralAuthorityPrivateKeyDecoded =
        "{\"privateKey\":{\"zpSubgroup\":{\"p\":\"AIGt8wzizyJ8+ia716YgY4FjG5gJRjfz+iB3OeWEMLCOLnoWG0wHwFQyo2VNx4lgBPDmSIb5NtJ/12U3dfe7JdgYjEMSaz9HUrfowHNwCuD1VVmDXxUvyxPSV5/iss7a85sopvR9n09imvvp8XDfPNuccd10TQwGSKVt2vN7vSMrgQOsGEuBBsEmsdlRil4+x9NTYphsc/7vTV9pRN4U+ZI5yTbBof6SFcH5mwAatlZB/RztwA1wh3qUUgyLz/kTKqTRbaPc5W1+LDPBZnMiaTWq786418pio4oM86mVIthfE/34S0kn8GpJGzNF12NzbVQzbpv6YpmrPKG1FfaQPwc=\",\"q\":\"QNb5hnFnkT59E13r0xAxwLGNzASjG/n9EDuc8sIYWEcXPQsNpgPgKhlRsqbjxLACeHMkQ3ybaT/rspu6+92S7AxGIYk1n6OpW/RgObgFcHqqrMGvipfliekrz/FZZ215zZRTej7Pp7FNffT4uG+ebc447romhgMkUrbteb3ekZXAgdYMJcCDYJNY7KjFLx9j6amxTDY5/3emr7Sibwp8yRzkm2DQ/0kK4PzNgA1bKyD+jnbgBrhDvUopBkXn/ImVUmi20e5ytr8WGeCzOZE0mtV351xr5TFRxQZ51MqRbC+J/vwlpJP4NSSNmaLrsbm2qhm3Tf0xTNWeUNqK+0gfgw==\",\"g\":\"Ag==\"},\"exponents\":[\"AA==\"]}}";

    private static ElectoralAuthorityService _sut;

    private static String testMember0 = "John";

    private static String testMember1 = "Peter";

    private static String authoritiesCAPublicKey =
        "-----BEGIN PUBLIC KEY-----\n" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn7Fk2ptRyMUfmEw9dFnI\n"
            + "KS79OlHR3EJEzSQ5QHKaW29fyRgHIBgUypjbnG+D/tpS3Uq0NVBhV+Px35v+BbTX\n"
            + "Vc2a4dNLqjEL4a9DqU0iSKZRo9NTW72YxgXKJXSuBv2JFij2tde6B6kbw0wYXz7D\n"
            + "L6XNtPYUhfUsVwqLqQoQ39aXW4/SDYurrTuRnyejmTHurqxPw+e2tUZFynv5oN/Z\n"
            + "npwvSLGo4FUh3hvrgAm+/jwQp2ksk2Loy0HC4KWwCqp3uFM3BSpJFrj6V1Pc0JJC\n"
            + "WkPMNeFSC3hULyDjZ1jEmNlZF1JA63mPZ5TsHooxzKHVi80WfaWrCvbotTKEerOh\n" + "OwIDAQAB\n"
            + "-----END PUBLIC KEY-----";

    private final String electoralAuthorityJSON_withoutStatus = "{" + //
        "    \"id\": \"16e020d934594544a6e17d1e410da513\"," + //
        "    \"defaultTitle\": \"Electoral authority\"," + //
        "    \"defaultDescription\": \"A  sample EA\"," + //
        "    \"alias\": \"EA1\"," + //
        "    \"electionEvent\": {" + //
        "        \"id\": \"0b149cfdaad04b04b990c3b1d4ca7639\"" + //
        "    }," + //
        "    \"minimumThreshold\": \"2\"," + //
        "    \"electoralBoard\": [" + //
        "        \"" + testMember0 + "\"," + //
        "        \"" + testMember1 + "\"" + //
        "    ]" + //
        "}"; //

    private final String electoralAuthorityJSON_withStatus = "{" + //
        "    \"id\": \"16e020d934594544a6e17d1e410da513\"," + //
        "    \"defaultTitle\": \"Electoral authority\"," + //
        "    \"defaultDescription\": \"A  sample EA\"," + //
        "    \"alias\": \"EA1\"," + //
        "    \"electionEvent\": {" + //
        "        \"id\": \"0b149cfdaad04b04b990c3b1d4ca7639\"" + //
        "    }," + //
        " 	 \"status\": \"READY\"," + "\"minimumThreshold\": \"2\"," + //
        "    \"electoralBoard\": [" + //
        "        \"" + testMember0 + "\"," + //
        "        \"" + testMember1 + "\"" + //
        "    ]" + //
        "}"; //

    private final String electionEventJSON = "{" + //
        "    \"id\": \"0b149cfdaad04b04b990c3b1d4ca7639\"," + //
        "    \"defaultTitle\": \"Spanish referendum\"," + //
        "    \"defaultDescription\": \"A sample election event for demo purposes\"," + //
        "    \"alias\": \"SP1\"," + //
        "    \"dateFrom\": \"16/10/2015 09:00\"," + //
        "    \"dateTo\": \"01/01/2016 19:00\"," + //
        "    \"administrationAuthority\": {" + //
        "        \"id\": \"04d7e562547646c2aec2ef12628dc126\"" + //
        "    }," + //
        "    \"settings\": {" + //
        "        \"electionEvent\": {" + //
        "            \"id\": \"0b149cfdaad04b04b990c3b1d4ca7639\"" + //
        "        }," + //
        "        \"encryptionParameters\": {" + //
        "            \"p\": \"16370518994319586760319791526293535327576438646782139419846004180837103527129035954742043590609421369665944746587885814920851694546456891767644945459124422553763416586515339978014154452159687109161090635367600349264934924141746082060353483306855352192358732451955232000593777554431798981574529854314651092086488426390776811367125009551346089319315111509277347117467107914073639456805159094562593954195960531136052208019343392906816001017488051366518122404819967204601427304267380238263913892658950281593755894747339126531018026798982785331079065126375455293409065540731646939808640273393855256230820509217411510058759\","
        + //
        "            \"q\": \"8185259497159793380159895763146767663788219323391069709923002090418551763564517977371021795304710684832972373293942907460425847273228445883822472729562211276881708293257669989007077226079843554580545317683800174632467462070873041030176741653427676096179366225977616000296888777215899490787264927157325546043244213195388405683562504775673044659657555754638673558733553957036819728402579547281296977097980265568026104009671696453408000508744025683259061202409983602300713652133690119131956946329475140796877947373669563265509013399491392665539532563187727646704532770365823469904320136696927628115410254608705755029379\","
        + //
        "            \"g\": \"2\"" + //
        "         }," + //
        "        \"certificatesValidityPeriod\": 1," + //
        "        \"challengeLength\": 16," + //
        "        \"challengeResponseExpirationTime\": 2000," + //
        "        \"authTokenExpirationTime\": 16000," + //
        "        \"numberVotesPerVotingCard\": 1," + //
        "        \"numberVotesPerAuthToken\": 1," + //
        "        \"maximumNumberOfAttempts\": 5" + //
        "    }" + //
        "}"; //

    @Injectable
    private ElectoralAuthorityRepository _electoralAuthorityRepository;

    @Injectable
    private BallotBoxRepository _ballotBoxRepository;

    @Injectable
    private ElectionEventRepository _electionEventRepository;

    @Injectable
    private ConfigurationEntityStatusService _configurationEntityStatusService;

    @Injectable
    private PathResolver _pathResolver;

    @Injectable
    private SmartCardConfig config = SmartCardConfig.SMART_CARD;

    @Injectable
    private CreateEBKeysSerializer _createEBKeysSerializer;

    @Injectable
    private ElectoralAuthorityDataGeneratorServiceImpl _electoralAuthorityDataGeneratorServiceImpl;

    @BeforeClass
    public static void init() throws IOException, GeneralCryptoLibException {
        Security.addProvider(new BouncyCastleProvider());

        _sut = new ElectoralAuthorityService();
        Deencapsulation.setField(_sut, "smartCardConfig", SmartCardConfig.SMART_CARD);
        Deencapsulation.setField(_sut, "transactionInfoProvider", new TransactionInfoProvider());
        Deencapsulation.setField(_sut, "secureLogger", Mockito.mock(SecureLoggingWriter.class));
        _sut.init();

    }

    @Test
    public void constituteTest(@Mocked final CreateSharesHandler createSharesHandlerElGamal)
            throws ResourceNotFoundException, SharesException, IOException, GeneralCryptoLibException {

        String electoralAuthorityId = "16e020d934594544a6e17d1e410da513";
        String electionEventId = "0b149cfdaad04b04b990c3b1d4ca7639";

        MockUp<ElectionEventRepository> electionEventRepositoryMockUp = new MockUp<ElectionEventRepository>() {

            @Mock
            public String find(final String id) {
                return electionEventJSON;
            }
        };

        Deencapsulation.setField(_sut, "_electionEventRepository", electionEventRepositoryMockUp.getMockInstance());

        MockUp<ElectoralAuthorityRepository> electoralAuthorityRepositoryMockUp =
            new MockUp<ElectoralAuthorityRepository>() {

                @Mock
                public String find(final String id) {
                    return electoralAuthorityJSON_withoutStatus;
                }
            };

        Deencapsulation.setField(_sut, "_electoralAuthorityRepository",
            electoralAuthorityRepositoryMockUp.getMockInstance());

        new Expectations() {
            {
                createSharesHandlerElGamal.generateAndSplit(2, 2);
                times = 1;
            }
        };

        _sut.constitute(electionEventId, electoralAuthorityId);
    }

    @Test
    public void activate() throws GeneralCryptoLibException {

        String pathToGiveToResolver = Paths.get("src/test/resources/").toAbsolutePath().toString();
        PathResolver initializedPathResolver = new PrefixPathResolver(pathToGiveToResolver);
        Deencapsulation.setField(_sut, "_pathResolver", initializedPathResolver);

        String electoralAuthorityId = "16e020d934594544a6e17d1e410da513";
        String electionEventId = "0b149cfdaad04b04b990c3b1d4ca7639";

        ActivateOutputData output = _sut.activate(electionEventId, electoralAuthorityId);

        assertThat(output.getIssuerPublicKeyPEM().isEmpty(), is(false));
        assertThat(output.getSerializedSubjectPublicKey().isEmpty(), is(false));

        ElGamalPublicKey serializedElectoralAuthorityPublicKeyObject =
            ElGamalPublicKey.fromJson(serializedElectoralAuthorityPublicKeyDecoded);

        ElGamalPublicKey serializedSubjectPublicKeyObject = ElGamalPublicKey.fromJson(
            new String(Base64.getDecoder().decode(output.getSerializedSubjectPublicKey()), StandardCharsets.UTF_8));

        assertThat(serializedElectoralAuthorityPublicKeyObject.equals(serializedSubjectPublicKeyObject), is(true));

    }

    @Test
    public void readShareTest() throws SharesException, GeneralCryptoLibException, ResourceNotFoundException {

        String electoralAuthorityId = "16e020d934594544a6e17d1e410da513";
        String electionEventId = "0b149cfdaad04b04b990c3b1d4ca7639";
        String pin = "222222";
        String hashMember = getHashValueForMember(testMember0);
        String label = hashMember.substring(0, Math.min(hashMember.length(), Constants.SMART_CARD_LABEL_MAX_LENGTH));

        MockUp<StatelessReadSharesHandler> statelessReader = new MockUp<StatelessReadSharesHandler>() {

            @Mock
            public String readShareAndStringify(final String pin, final PublicKey publicKey) {
                return "";
            }

            @Mock
            public String getSmartcardLabel() {
                return label;
            }

        };

        StatelessReadSharesHandler statelessReaderMockInstance = statelessReader.getMockInstance();
        Deencapsulation.setField(_sut, "_statelessReadSharesHandler", statelessReaderMockInstance);

        PublicKey publicKey =
            com.scytl.cryptolib.primitives.primes.utils.PemUtils.publicKeyFromPem(authoritiesCAPublicKey);

        MockUp<ElectoralAuthorityRepository> electoralAuthorityRepositoryMockUp =
            new MockUp<ElectoralAuthorityRepository>() {

                @Mock
                public String find(final String id) {
                    return electoralAuthorityJSON_withoutStatus;
                }
            };

        Deencapsulation.setField(_sut, "_electoralAuthorityRepository",
            electoralAuthorityRepositoryMockUp.getMockInstance());

        new Expectations() {
            {
                statelessReaderMockInstance.readShareAndStringify(pin, publicKey);
            }
        };

        _sut.readShare(electionEventId, electoralAuthorityId, 0, pin, authoritiesCAPublicKey);
    }

    @Test
    public void reconstructPrivateKey() throws GeneralCryptoLibException, SharesException {

        String electoralAuthorityId = "16e020d934594544a6e17d1e410da513";
        String electionEventId = "0b149cfdaad04b04b990c3b1d4ca7639";

        ElGamalPrivateKey elGamalPrivateKey = ElGamalPrivateKey.fromJson(serializedElectoralAuthorityPrivateKeyDecoded);
        ElGamalPrivateKeyAdapter electoralAuthorityPrivateKey = new ElGamalPrivateKeyAdapter(elGamalPrivateKey);

        MockUp<StatelessReadSharesHandler> statelessReader = new MockUp<StatelessReadSharesHandler>() {

            @Mock
            public PrivateKey getPrivateKeyWithSerializedShares(final Set<String> shares, final PublicKey publicKey) {
                return electoralAuthorityPrivateKey;
            }

        };

        StatelessReadSharesHandler statelessReaderMockInstance = statelessReader.getMockInstance();
        Deencapsulation.setField(_sut, "_statelessReadSharesHandler", statelessReaderMockInstance);

        String serializedPrivateKey = _sut.reconstruct(electoralAuthorityId, new ArrayList<>(), serializedElectoralAuthorityPublicKey);

        ElGamalPrivateKey serializedPrivateKeyObject = ElGamalPrivateKey
            .fromJson(new String(Base64.getDecoder().decode(serializedPrivateKey), StandardCharsets.UTF_8));
        ElGamalPrivateKey serializedElectoralAuthorityPrivateKeyObject = ElGamalPrivateKey.fromJson(
            new String(Base64.getDecoder().decode(serializedElectoralAuthorityPrivateKey), StandardCharsets.UTF_8));

        assertThat(serializedElectoralAuthorityPrivateKeyObject.equals(serializedPrivateKeyObject), is(true));

    }

    @Test
    public void not_sign_an_electoral_authority_without_status()
            throws IOException, ResourceNotFoundException, GeneralCryptoLibException {

        String electionEventId = "0b149cfdaad04b04b990c3b1d4ca7639";
        String electoralAuthorityId = "16e020d934594544a6e17d1e410da513";

        MockUp<ElectoralAuthorityRepository> electoralAuthorityRepositoryMockUp =
            new MockUp<ElectoralAuthorityRepository>() {

                @Mock
                public String find(final String id) {
                    return electoralAuthorityJSON_withoutStatus;
                }
            };

        Deencapsulation.setField(_sut, "_electoralAuthorityRepository",
            electoralAuthorityRepositoryMockUp.getMockInstance());

        assertThat(_sut.sign(electionEventId, electoralAuthorityId, SigningTestData.PRIVATE_KEY_PEM), is(false));
    }

    @Test
    public void sign() throws IOException, ResourceNotFoundException, GeneralCryptoLibException {

        String electionEventId = "0b149cfdaad04b04b990c3b1d4ca7639";
        String electoralAuthorityId = "16e020d934594544a6e17d1e410da513";

        MockUp<ElectoralAuthorityRepository> electoralAuthorityRepositoryMockUp =
            new MockUp<ElectoralAuthorityRepository>() {

                @Mock
                public String find(final String id) {
                    return electoralAuthorityJSON_withStatus;
                }
            };

        Deencapsulation.setField(_sut, "_electoralAuthorityRepository",
            electoralAuthorityRepositoryMockUp.getMockInstance());

        String pathToGiveToResolver = Paths.get("src/test/resources/").toAbsolutePath().toString();
        PathResolver initializedPathResolver = new PrefixPathResolver(pathToGiveToResolver);
        Deencapsulation.setField(_sut, "_pathResolver", initializedPathResolver);

        MockUp<ConfigurationEntityStatusService> configurationEntityStatusServiceMockUp =
            new MockUp<ConfigurationEntityStatusService>() {

                @Mock
                public String updateWithSynchronizedStatus(final String status, final String id,
                        final EntityRepository repository, final SynchronizeStatus syncDetails) {
                    return "";
                }
            };

        Deencapsulation.setField(_sut, "_statusService", configurationEntityStatusServiceMockUp.getMockInstance());

        assertThat(_sut.sign(electionEventId, electoralAuthorityId, SigningTestData.PRIVATE_KEY_PEM), is(true));

        Path outputPath = Paths.get("src/test/resources/sdm/config/0b149cfdaad04b04b990c3b1d4ca7639/ONLINE");

        Path signedAuthenticationContextDataJSON = Paths.get(outputPath.toString(), "authentication",
            ConfigConstants.CONFIG_FILE_NAME_SIGNED_AUTH_CONTEXT_DATA);
        Path signedAuthenticationVoterDataJSON =
            Paths.get(outputPath.toString(), "authentication", ConfigConstants.CONFIG_FILE_NAME_SIGNED_AUTH_VOTER_DATA);
        Path signedElectionInformationContentsJSON = Paths.get(outputPath.toString(), "electionInformation",
            ConfigConstants.CONFIG_FILE_NAME_SIGNED_ELECTION_INFORMATION_CONTENTS);
        Path signedElectoralAuthorityJSON = Paths.get(outputPath.toString(), "electoralAuthorities",
            electoralAuthorityId, ConfigConstants.CONFIG_FILE_NAME_SIGNED_ELECTORAL_AUTHORITY_JSON);

        assertThatFilesExist(signedAuthenticationContextDataJSON, signedAuthenticationVoterDataJSON,
            signedElectionInformationContentsJSON, signedElectoralAuthorityJSON);

        verifySignaturesAndDeleteFiles(signedAuthenticationContextDataJSON, signedAuthenticationVoterDataJSON,
            signedElectionInformationContentsJSON, signedElectoralAuthorityJSON);
    }

    private void verifySignaturesAndDeleteFiles(final Path signedAuthenticationContextDataJSON,
            final Path signedAuthenticationVoterDataJSON, final Path signedElectionInformationContentsJSON,
            final Path signedElectoralAuthorityJSON) throws GeneralCryptoLibException, IOException {
        ConfigObjectMapper mapper = new ConfigObjectMapper();
        JSONVerifier verifier = new JSONVerifier();
        PublicKey publicKey = PemUtils.publicKeyFromPem(SigningTestData.PRIVATE_KEY_PEM);

        SignedObject signedAuthContextDataObj =
            mapper.fromJSONFileToJava(signedAuthenticationContextDataJSON.toFile(), SignedObject.class);
        String signatureAuthContextData = signedAuthContextDataObj.getSignature();
        verifier.verify(publicKey, signatureAuthContextData, AuthenticationContextData.class);
        Files.deleteIfExists(signedAuthenticationContextDataJSON);

        SignedObject signedAuthVoterDataObj =
            mapper.fromJSONFileToJava(signedAuthenticationVoterDataJSON.toFile(), SignedObject.class);
        String signatureAuthVoterData = signedAuthVoterDataObj.getSignature();
        verifier.verify(publicKey, signatureAuthVoterData, AuthenticationVoterData.class);
        Files.deleteIfExists(signedAuthenticationVoterDataJSON);

        SignedObject signedElectionInformationObj =
            mapper.fromJSONFileToJava(signedElectionInformationContentsJSON.toFile(), SignedObject.class);
        String signatureElectionInformation = signedElectionInformationObj.getSignature();
        verifier.verify(publicKey, signatureElectionInformation, ElectionInformationContents.class);
        Files.deleteIfExists(signedElectionInformationContentsJSON);

        SignedObject signedElectoralAuhtorityObj =
            mapper.fromJSONFileToJava(signedElectoralAuthorityJSON.toFile(), SignedObject.class);
        String signatureElectoralAuthority = signedElectoralAuhtorityObj.getSignature();
        verifier.verify(publicKey, signatureElectoralAuthority, ElectoralAuthority.class);
        Files.deleteIfExists(signedElectoralAuthorityJSON);
    }

    private void assertThatFilesExist(final Path signedAuthenticationContextDataJSON,
            final Path signedAuthenticationVoterDataJSON, final Path signedElectionInformationContentsJSON,
            final Path signedElectoralAuthorityJSON) {
        assertThat(Files.exists(signedAuthenticationContextDataJSON), is(true));
        assertThat(Files.exists(signedAuthenticationVoterDataJSON), is(true));
        assertThat(Files.exists(signedElectionInformationContentsJSON), is(true));
        assertThat(Files.exists(signedElectoralAuthorityJSON), is(true));
    }

    private String getHashValueForMember(final String member) {

        String base64Value = null;

        try {
            MessageDigest mdEnc = MessageDigest.getInstance(Constants.MESSAGE_DIGEST_ALGORITHM);

            byte[] memberByteArray = member.getBytes(StandardCharsets.UTF_8);
            mdEnc.update(memberByteArray, 0, memberByteArray.length);

            base64Value = Base64.getEncoder().encodeToString(mdEnc.digest());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Cryptolib exception when getting hash for member: " + member, e);
        }

        return base64Value;
    }
}
