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

import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

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 com.scytl.products.ov.commons.beans.domain.model.receipt.Receipt;
import com.scytl.products.ov.commons.beans.exceptions.ApplicationException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBox;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBoxInformation;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBoxInformationRepository;
import com.scytl.products.ov.ei.services.domain.model.ballotbox.BallotBoxRepository;
import com.scytl.products.ov.ei.services.domain.model.castcode.VoteCastCode;
import com.scytl.products.ov.ei.services.domain.model.castcode.VoteCastCodeRepository;
import com.scytl.products.ov.ei.services.domain.service.vote.VoteServiceImpl;

@RunWith(MockitoJUnitRunner.class)
public class VoteServiceTest {

    @InjectMocks
    VoteServiceImpl voteService = new VoteServiceImpl();

    @Mock
    BallotBoxRepository ballotBoxRepositoryMock;

    @Mock
    BallotBoxInformationRepository ballotBoxInformationRepositoryMock;

    @Mock
    VoteCastCodeRepository voteCastCodeRepositoryMock;

    @Mock
    BallotBox ballotBoxMock;

    @Mock
    BallotBoxInformation ballotBoxInformationMock;

    @Mock
    VoteCastCode voteCastCodeMock;

    private String vote;

    private static final String voteWithMalformedReceipt =
        "{\"receipt\":{\"badfield1\":\"tralalalalalala\",\"anotherWrongField\":\"asldfjasljdflasjf\"}}";

    private static final String confirmationRequiredBallotBoxInformation = "{\"confirmationRequired\":true}";

    private static final String confirmationNotRequiredBallotBoxInformation = "{\"confirmationRequired\":false}";

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

    @Before
    public void init() {
        MockitoAnnotations.initMocks(VoteServiceTest.class);
    }

    @Test
    public void getVoteReceiptOk()
            throws ResourceNotFoundException, ApplicationException, IOException, URISyntaxException {

        Path votePath = getCurrentPath(Paths.get("ballotbox", "vote.json"));
        vote = new String(Files.readAllBytes(votePath));

        when(ballotBoxRepositoryMock.findByTenantIdElectionEventIdVotingCardId(anyString(), anyString(), anyString()))
            .thenReturn(ballotBoxMock);
        when(ballotBoxInformationRepositoryMock.findByTenantIdElectionEventIdBallotBoxId(anyString(), anyString(),
            anyString())).thenReturn(ballotBoxInformationMock);
        when(ballotBoxInformationMock.getJson()).thenReturn(confirmationRequiredBallotBoxInformation);

        when(ballotBoxMock.getVote()).thenReturn(vote);
        Receipt voteReceipt = voteService.getVoteReceipt("1", "1", "1");
        assertThat(voteReceipt, notNullValue());

    }

    @Test
    public void getVoteReceiptNotFound() throws ResourceNotFoundException, ApplicationException {

        expectedException.expect(ApplicationException.class);
        when(ballotBoxRepositoryMock.findByTenantIdElectionEventIdVotingCardId(anyString(), anyString(), anyString()))
            .thenThrow(new ResourceNotFoundException("exception"));
        voteService.getVoteReceipt("1", "1", "1");

    }

    @Test
    public void getVoteReceiptMalformed() throws ResourceNotFoundException, ApplicationException {

        expectedException.expect(ApplicationException.class);
        when(ballotBoxRepositoryMock.findByTenantIdElectionEventIdVotingCardId(anyString(), anyString(), anyString()))
            .thenReturn(ballotBoxMock);
        when(ballotBoxInformationRepositoryMock.findByTenantIdElectionEventIdBallotBoxId(anyString(), anyString(),
            anyString())).thenReturn(ballotBoxInformationMock);
        when(
            voteCastCodeRepositoryMock.findByTenantIdElectionEventIdVotingCardId(anyString(), anyString(), anyString()))
                .thenReturn(voteCastCodeMock);
        when(ballotBoxInformationMock.getJson()).thenReturn(confirmationRequiredBallotBoxInformation);
        when(ballotBoxMock.getVote()).thenReturn(voteWithMalformedReceipt);
        voteService.getVoteReceipt("1", "1", "1");

    }

    @Test
    public void getVoteReceiptMalformedConfirmationNotRequired()
            throws ResourceNotFoundException, ApplicationException {

        expectedException.expect(ApplicationException.class);
        when(ballotBoxRepositoryMock.findByTenantIdElectionEventIdVotingCardId(anyString(), anyString(), anyString()))
            .thenReturn(ballotBoxMock);
        when(ballotBoxInformationRepositoryMock.findByTenantIdElectionEventIdBallotBoxId(anyString(), anyString(),
            anyString())).thenReturn(ballotBoxInformationMock);
        when(
            voteCastCodeRepositoryMock.findByTenantIdElectionEventIdVotingCardId(anyString(), anyString(), anyString()))
                .thenReturn(voteCastCodeMock);
        when(ballotBoxInformationMock.getJson()).thenReturn(confirmationNotRequiredBallotBoxInformation);
        when(ballotBoxMock.getVote()).thenReturn(voteWithMalformedReceipt);
        voteService.getVoteReceipt("1", "1", "1");

    }

    private Path getCurrentPath(final Path path) throws URISyntaxException {

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL resource = classLoader.getResource(path.toString());
        return Paths.get(resource.toURI());

    }

}
