/*
 * 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.vw.services.infrastructure.remote;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;

import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.ov.commons.beans.domain.model.confirmation.ConfirmationMessage;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.exceptions.VoteCastCodeRepositoryException;
import com.scytl.products.ov.commons.beans.validation.CryptographicOperationException;
import com.scytl.products.ov.commons.dto.CastCodeAndComputeResults;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.vw.infrastructure.log.SecureLoggerInformation;
import com.scytl.products.ov.vw.services.domain.model.authentication.AuthenticationToken;
import com.scytl.products.ov.vw.services.domain.model.confirmation.VoteCastCodeRepository;
import com.scytl.products.ov.vw.services.domain.model.information.VoterInformation;

@RunWith(MockitoJUnitRunner.class)
public class VoteCastCodeRepositoryDecoratorTest {

    private static final String VOTING_CARD_ID = "11";

    private static final String AUTHENTICATION_TOKEN_SIGNATURE = "signature";

    private final String TENANT_ID = "100";

    private final String ELECTION_EVENT_ID = "1";

    private final String VERIFICATION_CARD_ID = "1";

    @Mock
    private VoteCastCodeRepository voteCastCodeRepository;

    @Mock
    private TrackIdInstance trackIdInstance;

    @Mock
    private SecureLoggingWriter secureLoggerWriter;

    @Mock
    private SecureLoggerInformation secureLoggerInformation;

    @InjectMocks
    VoteCastCodeRepositoryDecorator rut = new VoteCastCodeRepositoryDecorator();

    @BeforeClass
    public static void setup() {
        MockitoAnnotations.initMocks(VoteCastCodeRepositoryDecoratorTest.class);
        Security.addProvider(new BouncyCastleProvider());
    }

    @Before
    public void init() {
        when(secureLoggerInformation.getAuthenticationTokenObject())
            .thenReturn(new AuthenticationToken(new VoterInformation(), "authTokenIdBase64", "timestamp", "signature"));
    }

    @Test
    public void testGenerateCastCodeSuccessful() throws CryptographicOperationException {
        ConfirmationMessage confirmationMessage = new ConfirmationMessage();
        CastCodeAndComputeResults voteCastMessageMock = new CastCodeAndComputeResults();

        when(voteCastCodeRepository.generateCastCode(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID, VOTING_CARD_ID,
            AUTHENTICATION_TOKEN_SIGNATURE, confirmationMessage)).thenReturn(voteCastMessageMock);

        CastCodeAndComputeResults voteCastMessage = rut.generateCastCode(TENANT_ID, ELECTION_EVENT_ID,
            VERIFICATION_CARD_ID, VOTING_CARD_ID, AUTHENTICATION_TOKEN_SIGNATURE, confirmationMessage);

        assertEquals(voteCastMessageMock, voteCastMessage);
    }

    @Test(expected = CryptographicOperationException.class)
    public void testGenerateCastCodeCryptographicOperationException() throws CryptographicOperationException {
        ConfirmationMessage confirmationMessage = new ConfirmationMessage();

        when(voteCastCodeRepository.generateCastCode(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID, VOTING_CARD_ID,
            AUTHENTICATION_TOKEN_SIGNATURE, confirmationMessage))
                .thenThrow(new CryptographicOperationException("exception"));

        rut.generateCastCode(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID, VOTING_CARD_ID,
            AUTHENTICATION_TOKEN_SIGNATURE, confirmationMessage);
    }

    @Test
    public void testGetCastCodeSuccessful() throws ResourceNotFoundException, CryptographicOperationException {
        CastCodeAndComputeResults voteCastMessageMock = new CastCodeAndComputeResults();

        when(voteCastCodeRepository.getCastCode(TENANT_ID, ELECTION_EVENT_ID, ELECTION_EVENT_ID))
            .thenReturn(voteCastMessageMock);

        CastCodeAndComputeResults voteCastMessage = rut.getCastCode(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID);

        assertEquals(voteCastMessageMock, voteCastMessage);
    }

    @Test(expected = ResourceNotFoundException.class)
    public void testGetCastCodeResourceNotFoundException()
            throws ResourceNotFoundException, CryptographicOperationException {
        when(voteCastCodeRepository.getCastCode(TENANT_ID, ELECTION_EVENT_ID, ELECTION_EVENT_ID))
            .thenThrow(new ResourceNotFoundException("exception"));
        rut.getCastCode(TENANT_ID, ELECTION_EVENT_ID, ELECTION_EVENT_ID);
    }

    @Test
    public void testStoreCastCodeSuccessful() throws ResourceNotFoundException {
        CastCodeAndComputeResults voteCastMessageMock = new CastCodeAndComputeResults();

        when(voteCastCodeRepository.storesCastCode(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID,
            voteCastMessageMock)).thenReturn(true);

        boolean result = rut.storesCastCode(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID, voteCastMessageMock);

        assertEquals(true, result);
    }

    @Test(expected = ResourceNotFoundException.class)
    public void testStoreCastCodeResourceNotFoundException() throws ResourceNotFoundException {
        CastCodeAndComputeResults voteCastMessageMock = new CastCodeAndComputeResults();

        when(voteCastCodeRepository.storesCastCode(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID,
            voteCastMessageMock)).thenThrow(new ResourceNotFoundException("exception"));

        rut.storesCastCode(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID, voteCastMessageMock);
    }

    @Test
    public void testVoteCastCodeExistsSuccessful() throws VoteCastCodeRepositoryException {
        when(voteCastCodeRepository.voteCastCodeExists(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID))
            .thenReturn(true);
        boolean result = rut.voteCastCodeExists(TENANT_ID, ELECTION_EVENT_ID, VERIFICATION_CARD_ID);
        assertEquals(true, result);
    }

}
