/*
 * 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.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import javax.json.Json;
import javax.json.JsonObjectBuilder;

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.runners.MockitoJUnitRunner;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.products.oscore.logging.api.domain.Level;
import com.scytl.products.oscore.logging.api.domain.LogContent;
import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.ov.commons.beans.domain.model.vote.Vote;
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.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.rule.ElectionDatesRule;
import com.scytl.products.ov.ei.services.domain.model.rule.ElectionDatesRuleDecorator;
import com.scytl.products.ov.ei.services.infrastructure.log.SecureLoggerHelper;

/**
 *
 */
@RunWith(MockitoJUnitRunner.class)
public class ElectionDatesRuleDecoratorTest {

    private Vote vote;

    private DateTimeFormatter formatter;

    private static String ballotBoxId = "73783638d2984205b821f38e82e265c5";

    private static String votingCardId = "73553638d2984205b821f38e82e265c5";

    private static Long days_4 = 4L;

    private static Long days_8 = 8L;

    private static LocalDateTime now;

    private String authenticationToken =
        "{\"id\": \"lnniWSgf+XDd4dasaIX9rQ==\",\"voterInformation\": {\"electionEventId\": \"100\","
            + "\"votingCardId\": \"100\",\"ballotId\": \"100\",\"verificationCardId\": \"100\",\"tenantId\":\"100\",\"ballotBoxId\": \"100\",\"votingCardSetId\": \"100\",\"credentialId\":\"100\","
            + "\"verificationCardSetId\": \"100\"},\"timestamp\": \"1430759337499\",\"signature\": \"base64encodedSignature==\"}";

    @InjectMocks
    private ElectionDatesRuleDecorator rule = new ElectionDatesRuleDecorator();

    @Mock
    private BallotBoxInformationRepository ballotBoxInformationRepository;

    @Mock
    private ElectionDatesRule electionDatesRule;

    @Mock
    private TrackIdInstance trackId;

    @Mock
    private SecureLoggingWriter secureLoggerWriter;

    @Mock
    private SecureLoggerHelper secureLoggerHelper;

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

    @Before
    public void setup() {
        vote = new Vote();
        vote.setBallotBoxId(ballotBoxId);
        vote.setAuthenticationToken(authenticationToken);
        vote.setVotingCardId(votingCardId);

        formatter = DateTimeFormatter.ISO_DATE_TIME;

        now = LocalDateTime.now();

        doNothing().when(secureLoggerWriter).log(any(Level.class), any(LogContent.class));
    }

    @Test
    public void electionInDatesTest() throws ResourceNotFoundException {
        JsonObjectBuilder jsonObject = Json.createObjectBuilder();
        BallotBoxInformation ballotBoxInformation = new BallotBoxInformation();
        jsonObject.add("startDate", now.minusDays(days_4).format(formatter)).add("endDate",
            now.plusDays(days_4).format(formatter));
        ballotBoxInformation.setJson(jsonObject.build().toString());
        when(
            ballotBoxInformationRepository.findByTenantIdElectionEventIdBallotBoxId(anyString(), anyString(),
                anyString())).thenReturn(ballotBoxInformation);
        ValidationError validationError = new ValidationError();
        validationError.setValidationErrorType(ValidationErrorType.SUCCESS);
        when(electionDatesRule.execute(vote)).thenReturn(validationError);
        assertTrue(rule.execute(vote).getValidationErrorType().equals(ValidationErrorType.SUCCESS));
    }

    @Test
    public void electionBeforeDateFrom() throws ResourceNotFoundException, GeneralCryptoLibException {

        JsonObjectBuilder jsonObject = Json.createObjectBuilder();
        BallotBoxInformation ballotBoxInformation = new BallotBoxInformation();

        jsonObject.add("startDate", now.plusDays(days_4).format(formatter)).add("endDate",
            now.plusDays(days_8).format(formatter));
        ballotBoxInformation.setJson(jsonObject.build().toString());
        when(
            ballotBoxInformationRepository.findByTenantIdElectionEventIdBallotBoxId(anyString(), anyString(),
                anyString())).thenReturn(ballotBoxInformation);
        ValidationError validationError = new ValidationError();
        validationError.setValidationErrorType(ValidationErrorType.ELECTION_OVER_DATE);
        when(electionDatesRule.execute(vote)).thenReturn(validationError);
        assertTrue(rule.execute(vote).getValidationErrorType().equals(ValidationErrorType.ELECTION_OVER_DATE));
    }

    @Test
    public void electionAfterDateTo() throws ResourceNotFoundException {

        JsonObjectBuilder jsonObject = Json.createObjectBuilder();
        BallotBoxInformation ballotBoxInformation = new BallotBoxInformation();

        jsonObject.add("startDate", now.minusDays(days_8).format(formatter)).add("endDate",
            now.minusDays(days_4).format(formatter));
        ballotBoxInformation.setJson(jsonObject.build().toString());
        when(
            ballotBoxInformationRepository.findByTenantIdElectionEventIdBallotBoxId(anyString(), anyString(),
                anyString())).thenReturn(ballotBoxInformation);
        ValidationError validationError = new ValidationError();
        validationError.setValidationErrorType(ValidationErrorType.ELECTION_OVER_DATE);
        when(electionDatesRule.execute(vote)).thenReturn(validationError);
        assertTrue(rule.execute(vote).getValidationErrorType().equals(ValidationErrorType.ELECTION_OVER_DATE));
    }

}
