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

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.mock;
import static org.mockito.Mockito.verify;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.Security;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
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.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.ov.channel.cc.commons.slogger.ServiceTransactionInfoProvider;
import com.scytl.products.ov.channel.cc.commons.util.FingerprintGenerator;
import com.scytl.products.ov.channel.cc.mixing.MixingKeyQueueTest.Config;
import com.scytl.products.ov.channel.cc.mixing.service.KeyRepositoryImpl;
import com.scytl.products.ov.channel.cc.mixing.service.MixingDecryptKeyGenerationServiceImpl;
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 = Config.class)
public class MixingKeyQueueTest {

    @Autowired
    private MessagingService messagingService;

    @Autowired
    private MixingDecryptKeyGenerationServiceImpl mixingDecryptKeyGenerationService;

    @BeforeClass
    public static void beforeClass() {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    @Test
    public void testKeyCreationHappyPath()
            throws GeneralCryptoLibException, DestinationNotFoundException, InvalidMessageException,
            MessagingException {
        ArgumentCaptor<KeyCreationDTO> returnedDTOs = ArgumentCaptor.forClass(KeyCreationDTO.class);
        KeyCreationDTO data = new KeyCreationDTO();
        data.setElectionEventId(UUID.randomUUID().toString());
        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());

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

        List<KeyCreationDTO> allValues = returnedDTOs.getAllValues();
        assertEquals(1, allValues.size());
        KeyCreationDTO returnedDTO = allValues.get(0);
        assertEquals(returnedDTO.getElectionEventId(), data.getElectionEventId());
        assertEquals(returnedDTO.getEncryptionParameters(), data.getEncryptionParameters());
        assertEquals(returnedDTO.getRequestId(), data.getRequestId());
        assertEquals(returnedDTO.getResourceId(), data.getResourceId());
        assertEquals(1, returnedDTO.getPublicKeys().size());
        assertEquals(KeyType.MIXING, returnedDTO.getPublicKeys().get(0).getKeytype());
        assertEquals(ElGamalPublicKey.fromJson(KeyManagerMockConfig.PUBLIC_KEY),
            returnedDTO.getPublicKeys().get(0).getPublicKey());
        assertArrayEquals("Signature".getBytes(StandardCharsets.UTF_8),
            returnedDTO.getPublicKeys().get(0).getKeySignature());
        assertNotNull(returnedDTO.getPublicKeys().get(0).getSignerCertificate());
    }

    @Configuration
    @Import({MixingDecryptKeyGenerationServiceImpl.class, KeyRepositoryImpl.class, KeyManagerMockConfig.class })
    static class Config {
        @Bean
        public MessagingService messagingService() {
            return mock(MessagingService.class);
        }

        @Bean
        public SecureLoggingWriter getSecureLoggingWriter() {
            return mock(SecureLoggingWriter.class);
        }

        @Bean
        public ServiceTransactionInfoProvider getServiceTransactionInfoProvider() {
            return new ServiceTransactionInfoProvider();
        }

        @Bean
        public FingerprintGenerator getFingerprintGenerator() {
            return mock(FingerprintGenerator.class);
        }
    }
}
