/*
 * 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.ei.services.domain.service.ballotbox;

import static com.scytl.products.ov.ei.services.domain.model.util.Constants.BALLOT_BOX_ID;
import static com.scytl.products.ov.ei.services.domain.model.util.Constants.ELECTION_EVENT_ID;
import static com.scytl.products.ov.ei.services.domain.model.util.Constants.TENANT_ID;
import static java.util.Collections.singleton;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;

import org.hamcrest.MatcherAssert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.Logger;

import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;

import com.scytl.products.ov.commons.beans.domain.model.EntityId;
import com.scytl.products.ov.commons.beans.exceptions.EntryPersistenceException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.beans.validation.ValidationErrorType;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.validation.ValidationError;
import com.scytl.products.ov.commons.validation.ValidationResult;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBoxInformationRepository;

/**
 * Test class to cover the decorator of the service
 */
@RunWith(MockitoJUnitRunner.class)
public class BallotBoxServiceDecoratorTest {
    private static final EntityId ENTITY_ID = new EntityId();
    static {
        ENTITY_ID.setId(BALLOT_BOX_ID);
    }

    @InjectMocks
    private BallotBoxServiceDecorator decorator = new BallotBoxServiceDecorator();

    @Mock
    private BallotBoxService ballotBoxService;

    @Mock
    private BallotBoxInformationRepository ballotBoxInformationRepository;

    @Mock
    private SecureLoggingWriter secureLoggerWriter;

    @Mock
    private TrackIdInstance trackId;

    @Mock
    private Logger logger;

    @Mock
    private OutputStream outputStream;

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @Before
    public void initMocks() {
        MockitoAnnotations.initMocks(this.getClass());
    }

    @Test
    public void blockBallotBox() throws EntryPersistenceException, ResourceNotFoundException {
        Collection<EntityId> ballotBoxIds = singleton(ENTITY_ID);
        decorator.blockBallotBoxes(TENANT_ID, ELECTION_EVENT_ID,
            ballotBoxIds);
        verify(ballotBoxService).blockBallotBoxes(TENANT_ID,
            ELECTION_EVENT_ID, ballotBoxIds);
    }

    @Test
    public void unblockBallotBox() throws EntryPersistenceException, ResourceNotFoundException {
        Collection<EntityId> ballotBoxIds = singleton(ENTITY_ID);
        decorator.unblockBallotBoxes(TENANT_ID, ELECTION_EVENT_ID,
            ballotBoxIds);
        verify(ballotBoxService).unblockBallotBoxes(TENANT_ID,
            ELECTION_EVENT_ID, ballotBoxIds);
    }

    @Test
    public void checkIfEmpty() {
        when(ballotBoxService.checkIfBallotBoxesAreEmpty(anyString(), anyString(), anyString()))
            .thenReturn(new ValidationResult(false));
        decorator.checkIfBallotBoxesAreEmpty(TENANT_ID, ELECTION_EVENT_ID, BALLOT_BOX_ID);
    }

    @Test
    public void checkIfTest() throws ResourceNotFoundException {
        when(ballotBoxService.checkIfTest(anyString(), anyString(), anyString())).thenReturn(false);
        decorator.checkIfTest(TENANT_ID, ELECTION_EVENT_ID, BALLOT_BOX_ID);
    }

    @Test
    public void isBlockedBallotBox() throws ResourceNotFoundException {
        when(ballotBoxService.isBlockedBallotBox(anyString(), anyString(), anyString())).thenReturn(true);
        final boolean blockedBallotBox = decorator.isBlockedBallotBox(TENANT_ID, ELECTION_EVENT_ID, BALLOT_BOX_ID);
        assertTrue(blockedBallotBox);
    }

    @Test
    public void validateBallotBoxNotBlocked() throws ResourceNotFoundException {

        when(ballotBoxService.validateBallotBoxNotBlocked(anyString(), anyString(), anyString()))
            .thenReturn(new ValidationError(ValidationErrorType.SUCCESS));
        final ValidationError error =
            decorator.validateBallotBoxNotBlocked(TENANT_ID, ELECTION_EVENT_ID, BALLOT_BOX_ID);
        MatcherAssert.assertThat(error.getValidationErrorType(), is(ValidationErrorType.SUCCESS));
    }

    @Test
    public void validateBallotBoxNotBlockedFails() throws ResourceNotFoundException {

        when(ballotBoxService.validateBallotBoxNotBlocked(anyString(), anyString(), anyString()))
            .thenReturn(new ValidationError(ValidationErrorType.BLOCKED_BALLOT_BOX));
        final ValidationError error =
            decorator.validateBallotBoxNotBlocked(TENANT_ID, ELECTION_EVENT_ID, BALLOT_BOX_ID);
        MatcherAssert.assertThat(error.getValidationErrorType(), is(ValidationErrorType.BLOCKED_BALLOT_BOX));
    }

    @Test
    public void validateBallotBoxNotBlockedThrowsException() throws ResourceNotFoundException {

        expectedException.expect(ResourceNotFoundException.class);
        when(ballotBoxService.validateBallotBoxNotBlocked(anyString(), anyString(), anyString()))
            .thenThrow(new ResourceNotFoundException("exception"));
        decorator.validateBallotBoxNotBlocked(TENANT_ID, ELECTION_EVENT_ID, BALLOT_BOX_ID);
    }

    @Test
    public void writeEncryptedBallotBox() throws IOException {
        doNothing().when(ballotBoxService).writeEncryptedBallotBox(any(OutputStream.class), anyString(), anyString(),
            anyString(), anyBoolean());
        decorator.writeEncryptedBallotBox(outputStream, TENANT_ID, ELECTION_EVENT_ID, BALLOT_BOX_ID, true);
    }

    @Test
    public void writeEncryptedBallotBoxIOException() throws IOException {

        expectedException.expect(IOException.class);
        doThrow(IOException.class).when(ballotBoxService).writeEncryptedBallotBox(any(OutputStream.class), anyString(),
            anyString(), anyString(), anyBoolean());
        decorator.writeEncryptedBallotBox(outputStream, TENANT_ID, ELECTION_EVENT_ID, BALLOT_BOX_ID, true);
    }
}
