/*
 * 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.channel.cc.choicecodes.generation;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.elgamal.bean.ElGamalEncryptionParameters;
import com.scytl.cryptolib.elgamal.bean.ElGamalPublicKey;
import com.scytl.products.ov.channel.cc.choicecodes.generation.service.ChoiceCodesKeyGenerationServiceImpl;
import com.scytl.products.ov.commons.dto.KeyCreationDTO;
import com.scytl.products.ov.commons.dto.KeyType;
import com.scytl.products.ov.commons.messaging.DestinationNotFoundException;
import com.scytl.products.ov.commons.messaging.InvalidMessageException;
import com.scytl.products.ov.commons.messaging.MessagingException;
import com.scytl.products.ov.commons.messaging.MessagingService;
import com.scytl.products.ov.commons.messaging.Queue;

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class ChoiceCodeKeyGenerationQueueRetryTest {

    @Autowired
    private MessagingService messagingService;
    
    @Autowired
    private ChoiceCodesKeyGenerationServiceImpl service;

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

    @Test
    public void testKeyCreationWithRetry()
            throws GeneralCryptoLibException, DestinationNotFoundException,
            InvalidMessageException, MessagingException {
    	
        KeyCreationDTO data = new KeyCreationDTO();
        String electionId = UUID.randomUUID().toString();
		data.setElectionEventId(electionId);
        ElGamalEncryptionParameters encryptionParameters =
            new ElGamalEncryptionParameters(new BigInteger("809"),
                new BigInteger("68"), new BigInteger("3"));
        data.setEncryptionParameters(encryptionParameters.toJson());
        data.setRequestId(UUID.randomUUID().toString());
        data.setResourceId(UUID.randomUUID().toString());

        ArgumentCaptor<KeyCreationDTO> returnedDTOs =
            ArgumentCaptor.forClass(KeyCreationDTO.class);

        service.onMessage(data);
        verify(messagingService, atLeastOnce()).send(any(Queue.class), returnedDTOs.capture());
        service.onMessage(data);
        verify(messagingService, atLeastOnce()).send(any(Queue.class), returnedDTOs.capture());

        List<KeyCreationDTO> allValues = returnedDTOs.getAllValues();
        List<KeyCreationDTO> valid = new ArrayList<>(2);
        for (KeyCreationDTO keyCreationDTO : allValues) {
			if(electionId.equals(keyCreationDTO.getElectionEventId())){
				valid.add(keyCreationDTO);
			}
		}
       for (KeyCreationDTO returnedDTO : valid) {
		
	        assertEquals(returnedDTO.getElectionEventId(),
	            data.getElectionEventId());
	        assertEquals(returnedDTO.getEncryptionParameters(),
	            data.getEncryptionParameters());
	        assertEquals(returnedDTO.getRequestId(), data.getRequestId());
	        assertEquals(returnedDTO.getResourceId(), data.getResourceId());
	        assertEquals(2, returnedDTO.getPublicKeys().size());
	        assertEquals(KeyType.CHOICE_CODE_GENERATION,
	            returnedDTO.getPublicKeys().get(0).getKeytype());
	        assertEquals(ElGamalPublicKey.fromJson(TestConfiguration.PUBLIC_KEY),
	            returnedDTO.getPublicKeys().get(0).getPublicKey());
	        assertArrayEquals("Signature".getBytes(StandardCharsets.UTF_8),
	            returnedDTO.getPublicKeys().get(0).getKeySignature());
	        assertNotNull(
	            returnedDTO.getPublicKeys().get(0).getSignerCertificate());
	        assertEquals(KeyType.CHOICE_CODE_DECRYPTION,
	            returnedDTO.getPublicKeys().get(1).getKeytype());
	        assertEquals(ElGamalPublicKey.fromJson(TestConfiguration.PUBLIC_KEY),
	            returnedDTO.getPublicKeys().get(1).getPublicKey());
	        assertArrayEquals("Signature".getBytes(StandardCharsets.UTF_8),
	            returnedDTO.getPublicKeys().get(1).getKeySignature());
	        assertNotNull(
	            returnedDTO.getPublicKeys().get(1).getSignerCertificate());
		}
    }

}
