/*
 * 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.sdm.infrastructure.preconfiguration;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectReader;
import com.scytl.products.oscore.logging.api.writer.SecureLoggingWriter;
import com.scytl.products.oscore.logging.core.provider.TransactionInfoProvider;
import com.scytl.products.ov.commons.infrastructure.config.InfrastructureConfig;
import com.scytl.products.ov.sdm.application.service.HashService;
import com.scytl.products.ov.sdm.domain.model.ballot.BallotRepository;
import com.scytl.products.ov.sdm.domain.model.ballotbox.BallotBoxRepository;
import com.scytl.products.ov.sdm.domain.model.ballottext.BallotTextRepository;
import com.scytl.products.ov.sdm.domain.model.electionevent.ElectionEventRepository;
import com.scytl.products.ov.sdm.domain.model.electoralauthority.ElectoralAuthorityRepository;
import com.scytl.products.ov.sdm.domain.model.votingcardset.VotingCardSetRepository;
import com.scytl.products.ov.sdm.infrastructure.clients.AdminPortalClient;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import javax.ws.rs.core.MediaType;
import okhttp3.Headers;
import okhttp3.ResponseBody;
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.Mockito;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;
import retrofit2.Call;
import retrofit2.Response;

@RunWith(MockitoJUnitRunner.class)
public class PreconfigurationRepositoryImplDownloadTest {

    @Mock
    private ElectionEventRepository electionEventRepository;

    @Mock
    private BallotBoxRepository ballotBoxRepository;

    @Mock
    private BallotRepository ballotRepository;

    @Mock
    private BallotTextRepository ballotTextRepository;

    @Mock
    private VotingCardSetRepository votingCardSetRepository;

    @Mock
    private ElectoralAuthorityRepository electoralAuthorityRepository;

    @Mock
    private InfrastructureConfig infrastructureConfig;

    @Mock
    private AdminPortalClient clientMock;

    @Mock
    private ObjectReader objectReader;

    @Mock
    private SecureLoggingWriter secureLoggingWriter;

    @Mock
    private TransactionInfoProvider transactionInfoProvider;

    @Mock
    private HashService hashService;

    private String jsonCorrectLogin =
        "{\"username\":\"admin\",\"email\":\"admin@scytl.com\",\"firstName\":\"Admin\",\"lastName\":\"Admin\","
            + "\"token\":\"52a624e5a167494f9389c821e72a111e\",\"role\":\"ADMIN\",\"errors\":[]}";

    private Integer statusCodeNotFound = javax.ws.rs.core.Response.Status.NOT_FOUND.getStatusCode();

    private String configFile = "";

    @InjectMocks
    @Spy
    private PreconfigurationRepositoryImpl preconfigurationRepository = new PreconfigurationRepositoryImpl();

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

    @Before
    public void injectValueAnnotatedFields() {
      ReflectionTestUtils.setField(preconfigurationRepository, "tenantId", "tenant");
      ReflectionTestUtils.setField(preconfigurationRepository, "adminPortalBaseURL", "http://1.2.3");
    }

    @Test
    public void downloadFailedToGet() throws IOException, URISyntaxException {
        @SuppressWarnings("unchecked")
		Call<ResponseBody> loginCallMock = (Call<ResponseBody>) Mockito.mock(Call.class);
    	Headers headers = new Headers.Builder().add("Set-Cookie", "JSESSIONID=68DC1A66EDEE17F82AB48DC9C4F13277").build();
		when(loginCallMock.execute()).thenReturn(Response.success(ResponseBody.create(okhttp3.MediaType.parse(MediaType.APPLICATION_JSON), jsonCorrectLogin.getBytes()), headers));

        JsonNode jsonNode = mock(JsonNode.class, RETURNS_DEEP_STUBS);
        when(jsonNode.has(eq("token"))).thenReturn(true);
        when(jsonNode.get(eq("token")).asText()).thenReturn("52a624e5a167494f9389c821e72a111e");
        
		@SuppressWarnings("unchecked")
		Call<ResponseBody> exportCallMock = (Call<ResponseBody>) Mockito.mock(Call.class);
		when(exportCallMock.execute()).thenReturn(Response.error(statusCodeNotFound, ResponseBody.create(okhttp3.MediaType.parse(MediaType.APPLICATION_JSON), "ok".getBytes())));

        doReturn(clientMock).when(preconfigurationRepository).getAdminPortalClient(anyString());
        when(objectReader.readTree(any(InputStream.class))).thenReturn(jsonNode);
        when(clientMock.export(anyString())).thenReturn(exportCallMock);

        try {
          preconfigurationRepository.download(configFile);
          fail("Did not fail as it was supposed to");
        } catch (IOException e) {
          assertThat(e.getMessage(),
              is("Error downloading data from administrator portal. Status code: "
                  + statusCodeNotFound + "."));
        }
    }

    @Test
    public void download() throws IOException, URISyntaxException {

        @SuppressWarnings("unchecked")
		Call<ResponseBody> loginCallMock = (Call<ResponseBody>) Mockito.mock(Call.class);
    	Headers headers = new Headers.Builder().add("Set-Cookie", "JSESSIONID=68DC1A66EDEE17F82AB48DC9C4F13277").build();
		when(loginCallMock.execute()).thenReturn(Response.success(ResponseBody.create(okhttp3.MediaType.parse(MediaType.APPLICATION_JSON), jsonCorrectLogin.getBytes()), headers));
		
		@SuppressWarnings("unchecked")
		Call<ResponseBody> exportCallMock = (Call<ResponseBody>) Mockito.mock(Call.class);
		when(exportCallMock.execute()).thenReturn(Response.success(ResponseBody.create(okhttp3.MediaType.parse(MediaType.APPLICATION_JSON), "ok".getBytes())));


        JsonNode jsonNode = mock(JsonNode.class, RETURNS_DEEP_STUBS);
        when(jsonNode.has(eq("token"))).thenReturn(true);
        when(jsonNode.get(eq("token")).asText()).thenReturn("52a624e5a167494f9389c821e72a111e");

        doReturn(clientMock).when(preconfigurationRepository).getAdminPortalClient(anyString());
        when(objectReader.readTree(any(InputStream.class))).thenReturn(jsonNode);
        when(clientMock.export(anyString())).thenReturn(exportCallMock);

        doNothing().when(preconfigurationRepository).saveJson(anyString(), anyString());

        boolean result = preconfigurationRepository.download(configFile);

        assertThat(true, is(result));
    }

}
