/*
 * 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.vw.services.infrastructure.remote;

import static org.junit.Assert.*;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
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.exceptions.ApplicationException;
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.ui.ws.rs.ObjectMappers;
import com.scytl.products.ov.commons.validation.ValidationError;
import com.scytl.products.ov.commons.validation.ValidationResult;
import com.scytl.products.ov.vw.infrastructure.log.SecureLoggerInformation;
import com.scytl.products.ov.vw.services.domain.model.authentication.AuthenticationToken;
import com.scytl.products.ov.vw.services.domain.model.authentication.AuthenticationTokenMessage;
import com.scytl.products.ov.vw.services.domain.model.authentication.AuthenticationTokenRepository;
import com.scytl.products.ov.vw.services.domain.model.authentication.ChallengeInformation;
import com.scytl.products.ov.vw.services.domain.model.information.VoterInformation;

import com.scytl.products.ov.commons.infrastructure.remote.client.RetrofitException;
import okhttp3.ResponseBody;

@RunWith(MockitoJUnitRunner.class)
public class AuthenticationTokenRepositoryDecoratorTest {
	
	private final String TENANT_ID = "100";
	private final String ELECTION_EVENT_ID = "1";
	private final String CREDENTIAL_ID = "1";
	
    @Mock
    private Logger LOG;

    @Mock
    private TrackIdInstance trackId;

    @Mock
    private SecureLoggingWriter secureLoggerWriter;

    @Mock
    private SecureLoggerInformation secureLoggerInformation;
    
    @Mock
    private AuthenticationTokenRepository authenticationTokenRepository;
	
	@InjectMocks
	AuthenticationTokenRepositoryDecorator rut;
	
	@BeforeClass
	public static void setup() 	{
		MockitoAnnotations.initMocks(AuthenticationTokenRepositoryDecoratorTest.class);
	    Security.addProvider(new BouncyCastleProvider());
	}
	
	@Before
	public void init()
	{
		// init common mockings
		when(secureLoggerInformation.getAuthenticationTokenObject()).thenReturn(new AuthenticationToken(new VoterInformation(), "authTokenIdBase64", "timestamp", "signature"));
	}
	

	@Test
	public void testGetAuthenticationTokenSuccessful() throws ResourceNotFoundException, ApplicationException {
		ChallengeInformation challengeInformation = new ChallengeInformation();
		AuthenticationTokenMessage authTokenMessageMock = new AuthenticationTokenMessage();
		
		when(authenticationTokenRepository.getAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, challengeInformation)).thenReturn(authTokenMessageMock);
		AuthenticationTokenMessage authTokenMessage = rut.getAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, challengeInformation);
		
		assertEquals(authTokenMessageMock, authTokenMessage);
	}
	
	@Test(expected=ResourceNotFoundException.class)
	public void testGetAuthenticationTokenResourceNotFoundException() throws ResourceNotFoundException, ApplicationException {
		ChallengeInformation challengeInformation = new ChallengeInformation();
		
		when(authenticationTokenRepository.getAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, challengeInformation)).thenThrow(new ResourceNotFoundException("exception"));

		rut.getAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, challengeInformation);
	}
	
	@Test(expected=ResourceNotFoundException.class)
	public void testGetAuthenticationTokenResource404Error() throws ResourceNotFoundException, ApplicationException {
		ChallengeInformation challengeInformation = new ChallengeInformation();
		
		RetrofitException retrofitErrorMock = new RetrofitException(404, ResponseBody.create(okhttp3.MediaType.parse("text/html"), new byte[0]));
		
		when(authenticationTokenRepository.getAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, challengeInformation)).thenThrow(retrofitErrorMock);

		rut.getAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, challengeInformation);
	}
	
	@Test(expected=ApplicationException.class)
	public void testGetAuthenticationTokenResource500Error() throws ResourceNotFoundException, ApplicationException {
		ChallengeInformation challengeInformation = new ChallengeInformation();
		
		RetrofitException retrofitErrorMock = new RetrofitException(500, ResponseBody.create(okhttp3.MediaType.parse("text/html"), new byte[0]));
		
		when(authenticationTokenRepository.getAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, challengeInformation)).thenThrow(retrofitErrorMock);

		rut.getAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, challengeInformation);
	}

	
	@Test
	public void testValidateAuthenticationTokenIsValidSuccessful() throws IOException, ResourceNotFoundException, ApplicationException {
		AuthenticationToken authTokenMock = new AuthenticationToken();
		
		ValidationResult validationResultMock = new ValidationResult();
		validationResultMock.setResult(true);
		validationResultMock.setValidationError(new ValidationError(ValidationErrorType.SUCCESS));
		
		when(authenticationTokenRepository.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock))).thenReturn(validationResultMock);
		ValidationResult validationResult = rut.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock));
		
		assertEquals(validationResultMock.isResult(), validationResult.isResult());
	}
	
	@Test
	public void testValidateAuthenticationTokenIsNotValidSuccessful() throws IOException, ResourceNotFoundException, ApplicationException {
		AuthenticationToken authTokenMock = new AuthenticationToken();
		
		ValidationResult validationResultMock = new ValidationResult();
		validationResultMock.setResult(false);
		validationResultMock.setValidationError(new ValidationError(ValidationErrorType.SUCCESS));
		
		when(authenticationTokenRepository.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock))).thenReturn(validationResultMock);
		ValidationResult validationResult = rut.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock));
		
		assertEquals(validationResultMock.isResult(), validationResult.isResult());
	}
	
	@Test(expected=ResourceNotFoundException.class)
	public void testValidateAuthenticationToken404Error() throws IOException, ResourceNotFoundException, ApplicationException {
		AuthenticationToken authTokenMock = new AuthenticationToken();
		
		RetrofitException retrofitErrorMock = new RetrofitException(404, ResponseBody.create(okhttp3.MediaType.parse("text/html"), new byte[0]));
		
		when(authenticationTokenRepository.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock))).thenThrow(retrofitErrorMock);
		rut.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock));
	}
	
	@Test(expected=ResourceNotFoundException.class)
	public void testValidateAuthenticationResourceNotFoundException() throws IOException, ResourceNotFoundException, ApplicationException {
		AuthenticationToken authTokenMock = new AuthenticationToken();
		
		when(authenticationTokenRepository.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock))).thenThrow(new ResourceNotFoundException("exception"));
		rut.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock));
	}
	
	@Test(expected=ApplicationException.class)
	public void testValidateAuthenticationToken500Error() throws IOException, ResourceNotFoundException, ApplicationException {
		AuthenticationToken authTokenMock = new AuthenticationToken();
		
		RetrofitException retrofitErrorMock = new RetrofitException(500, ResponseBody.create(okhttp3.MediaType.parse("text/html"), new byte[0]));
		
		when(authenticationTokenRepository.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock))).thenThrow(retrofitErrorMock);
		rut.validateAuthenticationToken(TENANT_ID, ELECTION_EVENT_ID, CREDENTIAL_ID, ObjectMappers.toJson(authTokenMock));
	}
}
