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

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;

import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Assert;
import org.junit.Test;

import com.scytl.products.ov.commons.dto.mixing.MixingPayload;

public class MixingDTOImplTest {

    private static final String ERROR_MESSAGE = "Error!";

    private static final String REQUEST_ID = "requestId";

    private static final Set<String> QUEUES_TO_VISIT =
        Stream.of("m1-req", "m2-req", "m3-req").collect(Collectors.toSet());

    private static final String NODE_NAME = "m1";

    @Test
    public void testConstructor() {
        MixingDTO sut = getInitialDTO();

        assertNull(sut.getError());

        assertNotNull(sut.getRequestId());
        assertNotNull(sut.getPayload());
        assertNotNull(sut.getQueuesToVisit());
        assertEquals(QUEUES_TO_VISIT.size(), sut.getQueuesToVisit().size());

        assertNull(sut.getLastQueueName());
    }

    @Test
    public void testErrorCondition() {
        MixingDTO sut = new MixingDTOImpl(REQUEST_ID, QUEUES_TO_VISIT, mock(MixingPayload.class));
        sut.setError(new RuntimeException(ERROR_MESSAGE));

        assertNotNull(sut.getError());
        assertEquals(ERROR_MESSAGE, sut.getError().getErrorMessage());
        assertEquals(MixingError.MAX_RETRIES, sut.getError().getRetriesLeft());

        String anotherErrorMessage = "Another error message";
        sut.setError(new IllegalStateException(anotherErrorMessage));

        assertEquals(anotherErrorMessage, sut.getError().getErrorMessage());
        assertEquals(MixingError.MAX_RETRIES - 1, sut.getError().getRetriesLeft());
    }

    @Test
    public void testOutputDTO() {
        MixingDTO referenceDTO = getInitialDTO();
        MixingDTO sut = getInitialDTO();
        String visitedQueue = QUEUES_TO_VISIT.iterator().next();

        sut.update(visitedQueue, NODE_NAME, mock(MixingPayload.class));

        assertNull(sut.getError());

        assertNotNull(sut.getQueuesToVisit());
        Assert.assertFalse(sut.getQueuesToVisit().contains(visitedQueue));
        assertEquals(NODE_NAME, sut.getLastNodeName());
        assertEquals(sut.getRequestId(), referenceDTO.getRequestId());
        assertNotEquals(sut.getPayload(), referenceDTO.getPayload());
    }

    @Test(expected = IllegalArgumentException.class)
    public void failOnConstructorWithNoQueues() {
        new MixingDTOImpl(REQUEST_ID, Collections.emptySet(), mock(MixingPayload.class));
    }

    @Test(expected = IllegalArgumentException.class)
    public void failOnOutputFromUnexpectedQueue() {
        MixingDTO sut = getInitialDTO();

        sut.update("xxx", NODE_NAME, mock(MixingPayload.class));
    }

    private MixingDTO getInitialDTO() {
        return new MixingDTOImpl(REQUEST_ID, QUEUES_TO_VISIT, mock(MixingPayload.class));
    }

}
