/*
 * 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.orchestrator.choicecodes.domain.services;

import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeoutException;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.Logger;

import com.scytl.products.ov.channel.cc.orchestrator.commons.polling.PollingService;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.dto.ChoiceCodeVerificationDTO;
import com.scytl.products.ov.commons.dto.ChoiceCodesVerificationDecryptResPayload;
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(MockitoJUnitRunner.class)
public class ChoiceCodesDecryptionContributionsServiceImplTest {
    private static String ccQueueNames;
    private static String ccTopicNames;
    
    @Mock
    private MessagingService messagingService;

    @Mock
    private ChoiceCodesDecryptionContributionsConsumer choiceCodesDecryptionContributionsConsumer;

    @Mock
    @ChoiceCodesDecryption
    private PollingService<List<byte[]>> pollingService;

    @Mock
    private Logger LOG;

    @InjectMocks
    private ChoiceCodesDecryptionContributionsServiceImpl sut = new ChoiceCodesDecryptionContributionsServiceImpl();

    private String trackingId = "trackingId";

    private String tenantId = "100";

    private String eeId = "eeId";

    private String verCardSetId = "verCardSetId";

    private String verCardId = "verCardId";

    private Queue[] queues = {new Queue("cv-dec-v1-res"), new Queue("cv-dec-v2-res"), new Queue("cv-dec-v3-res"), new Queue("cv-dec-v4-res") };

    @BeforeClass
    public static void beforeClass() {
        ccQueueNames = System.setProperty("cc_queue_names",
            "{\"g4\": {\"cg-comp\": {\"res\": \"cg-comp-g4-res\", \"req\": \"cg-comp-g4-req\"}, \"cg-keygen\": {\"res\": \"cg-keygen-g4-res\", \"req\": \"cg-keygen-g4-req\"}}, \"g3\": {\"cg-comp\": {\"res\": \"cg-comp-g3-res\", \"req\": \"cg-comp-g3-req\"}, \"cg-keygen\": {\"res\": \"cg-keygen-g3-res\", \"req\": \"cg-keygen-g3-req\"}}, \"g2\": {\"cg-comp\": {\"res\": \"cg-comp-g2-res\", \"req\": \"cg-comp-g2-req\"}, \"cg-keygen\": {\"res\": \"cg-keygen-g2-res\", \"req\": \"cg-keygen-g2-req\"}}, \"g1\": {\"cg-comp\": {\"res\": \"cg-comp-g1-res\", \"req\": \"cg-comp-g1-req\"}, \"cg-keygen\": {\"res\": \"cg-keygen-g1-res\", \"req\": \"cg-keygen-g1-req\"}}, \"v1\": {\"cv-comp\": {\"res\": \"cv-comp-v1-res\", \"req\": \"cv-comp-v1-req\"}, \"cv-dec\": {\"res\": \"cv-dec-v1-res\", \"req\": \"cv-dec-v1-req\"}}, \"v2\": {\"cv-comp\": {\"res\": \"cv-comp-v2-res\", \"req\": \"cv-comp-v2-req\"}, \"cv-dec\": {\"res\": \"cv-dec-v2-res\", \"req\": \"cv-dec-v2-req\"}}, \"v3\": {\"cv-comp\": {\"res\": \"cv-comp-v3-res\", \"req\": \"cv-comp-v3-req\"}, \"cv-dec\": {\"res\": \"cv-dec-v3-res\", \"req\": \"cv-dec-v3-req\"}}, \"m1\": {\"md-keygen\": {\"res\": \"md-keygen-m1-res\", \"req\": \"md-keygen-m1-req\"}, \"md-mixdec\": {\"res\": \"md-mixdec-m1-res\", \"req\": \"md-mixdec-m1-req\"}}, \"m3\": {\"md-keygen\": {\"res\": \"md-keygen-m3-res\", \"req\": \"md-keygen-m3-req\"}, \"md-mixdec\": {\"res\": \"md-mixdec-m3-res\", \"req\": \"md-mixdec-m3-req\"}}, \"m2\": {\"md-keygen\": {\"res\": \"md-keygen-m2-res\", \"req\": \"md-keygen-m2-req\"}, \"md-mixdec\": {\"res\": \"md-mixdec-m2-res\", \"req\": \"md-mixdec-m2-req\"}}, \"v4\": {\"cv-comp\": {\"res\": \"cv-comp-v4-res\", \"req\": \"cv-comp-v4-req\"}, \"cv-dec\": {\"res\": \"cv-dec-v4-res\", \"req\": \"cv-dec-v4-req\"}}}");
        ccTopicNames = System.setProperty("cc_topic_names", "{\"or-ha\": \"or-ha\"}");
    }
    
    @AfterClass
    public static void afterClass() {
        if (ccQueueNames != null) {
            System.setProperty("cc_queue_names", ccQueueNames);
        } else {
            System.clearProperty("cc_queue_names");
        }
        if (ccTopicNames != null) {
            System.setProperty("cc_topic_names", ccTopicNames);
        } else {
            System.clearProperty("cc_topic_names");
        }
    }
    
    @Test
    public void requestContributionsTest() throws ResourceNotFoundException, TimeoutException, IOException {
        String expected1 = "computed value1";
        String expected2 = "computed value2";

        ChoiceCodesVerificationDecryptResPayload payload =
            new ChoiceCodesVerificationDecryptResPayload();
        payload.setDecryptContributionResult(Arrays.asList(expected1, expected2));

        byte[] bytes;
        try (ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                ObjectOutputStream stream = new ObjectOutputStream(buffer)) {
            stream.writeObject(payload);
            bytes = buffer.toByteArray();
        }

        when(pollingService.getResults(any(UUID.class))).thenReturn(singletonList(bytes));

        List<ChoiceCodesVerificationDecryptResPayload> result = sut.requestChoiceCodesDecryptionContributionsSync(
            trackingId, tenantId, eeId, verCardSetId, verCardId, "gammaStr");

        assertEquals(1, result.size());
        assertEquals(expected1, result.get(0).getDecryptContributionResult().get(0));
        assertEquals(expected2, result.get(0).getDecryptContributionResult().get(1));
    }

    @Test
    public void consumeContributionsTest() throws MessagingException {
        sut.startup();

        verify(messagingService, times(1)).createReceiver(queues[0], choiceCodesDecryptionContributionsConsumer);
        verify(messagingService, times(1)).createReceiver(queues[1], choiceCodesDecryptionContributionsConsumer);
        verify(messagingService, times(1)).createReceiver(queues[2], choiceCodesDecryptionContributionsConsumer);
        verify(messagingService, times(1)).createReceiver(queues[3], choiceCodesDecryptionContributionsConsumer);
    }
}
