/*
 * 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.kt.ui.ws.rs.application.operation;

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 javax.servlet.http.HttpServletRequest;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;

import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.TestProperties;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.slf4j.Logger;

import com.scytl.products.ov.commons.beans.exceptions.ApplicationException;
import com.scytl.products.ov.commons.beans.exceptions.ResourceNotFoundException;
import com.scytl.products.ov.commons.tracking.TrackIdInstance;
import com.scytl.products.ov.commons.ui.ws.rs.exceptions.ApplicationExceptionHandler;
import com.scytl.products.ov.commons.ui.ws.rs.exceptions.ResourceNotFoundExceptionHandler;
import com.scytl.products.ov.commons.util.HttpRequestService;
import com.scytl.products.ov.kt.domain.model.electionevent.ElectionEventTranslation;
import com.scytl.products.ov.kt.domain.model.electionevent.ElectionEventTranslationList;
import com.scytl.products.ov.kt.domain.model.electionevent.ElectionEventTranslationRepository;
import com.scytl.products.ov.kt.services.ElectionEventTranslationService;

import java.util.Arrays;

/**
 * Test class for the endpoint of the BallotBoxResource class
 */

public class ElectionEventResourceTest extends JerseyTest {

    public static final String TENANT_ID = "tenantId";

    public static final String ELECTION_EVENT_ID = "electionEventId";

    public static final String ALIAS = "alias";

    public static final int NOT_FOUND = 404;

    public static final int OK = 200;

    public static final String BBID = "bbid";

    @Mock
    private HttpServletRequest servletRequest;

    @Mock
    private Logger logger;

    @Mock
    private TrackIdInstance trackIdInstance;

    @Mock
    private HttpRequestService httpRequestService;

    @Mock
    private ElectionEventTranslationService electionEventTranslationService;

    @Mock
    private ElectionEventTranslationRepository electionEventTranslationRepository;

    private static String tenantId = "100";

    private static String electionEventId = "100";

    private static String alias = "alias";

    private static String id = "100";

    private final static String PATH_GET_BY_ALIAS = "/keytranslation/electionevent/tenant/{tenantId}/alias/{alias}";

    private final static String PATH_GET_BY_ID =
        "/keytranslation/electionevent/tenant/{tenantId}/electionEvent/{electionEventId}";

    private final static String PATH_POST = "/keytranslation/electionevent/secured/tenant/{tenantId}";

    private ElectionEventResource resource;

    @Test
    public void getByAliasOk() throws ResourceNotFoundException {

        int expectedStatus = OK;

        ElectionEventTranslation translation = new ElectionEventTranslation();

        commonPreparation();

        when(electionEventTranslationRepository.findByAlias(anyString(), anyString())).thenReturn(translation);

        int status = target(PATH_GET_BY_ALIAS).resolveTemplate(TENANT_ID, tenantId)
            .resolveTemplate(ELECTION_EVENT_ID, electionEventId).resolveTemplate(ALIAS, alias).request().get()
            .getStatus();

        Assert.assertEquals(status, expectedStatus);

    }

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

        int expectedStatus = NOT_FOUND;

        commonPreparation();

        when(electionEventTranslationRepository.findByAlias(anyString(), anyString()))
            .thenThrow(ResourceNotFoundException.class);

        int status = target(PATH_GET_BY_ALIAS).resolveTemplate(TENANT_ID, tenantId)
            .resolveTemplate(ELECTION_EVENT_ID, electionEventId).resolveTemplate(ALIAS, alias).request().get()
            .getStatus();

        Assert.assertEquals(status, expectedStatus);

    }

    @Test
    public void getByIdOk() throws ResourceNotFoundException {

        int expectedStatus = OK;

        ElectionEventTranslation translation = new ElectionEventTranslation();

        commonPreparation();

        when(electionEventTranslationRepository.findByElectionEventId(anyString(), anyString()))
            .thenReturn(translation);

        int status = target(PATH_GET_BY_ID).resolveTemplate(TENANT_ID, tenantId)
            .resolveTemplate(ELECTION_EVENT_ID, electionEventId).resolveTemplate(BBID, id).request().get().getStatus();

        Assert.assertEquals(status, expectedStatus);

    }

    @Test
    public void getByIdNotFound() throws ResourceNotFoundException {

        int expectedStatus = NOT_FOUND;

        commonPreparation();

        when(electionEventTranslationRepository.findByElectionEventId(anyString(), anyString()))
            .thenThrow(ResourceNotFoundException.class);

        int status = target(PATH_GET_BY_ID).resolveTemplate(TENANT_ID, tenantId)
            .resolveTemplate(ELECTION_EVENT_ID, electionEventId).resolveTemplate(BBID, id).request().get().getStatus();

        Assert.assertEquals(status, expectedStatus);

    }

    @Test
    public void uploadTranslations() throws IllegalArgumentException {

        int expectedStatus = OK;

        final ElectionEventTranslationList translations = getTranslations();
        doNothing().when(electionEventTranslationService).save(anyString(), any());

        int status = target(PATH_POST).resolveTemplate(TENANT_ID, tenantId).request()
            .post(Entity.entity(translations, MediaType.APPLICATION_JSON_TYPE)).getStatus();
        Assert.assertEquals(status, expectedStatus);

    }

    private void commonPreparation() {
        when(servletRequest.getHeader("X-Request-ID")).thenReturn("request");
        when(servletRequest.getRemoteAddr()).thenReturn("");
        when(servletRequest.getLocalAddr()).thenReturn("");
    }

    @Override
    protected Application configure() {

        MockitoAnnotations.initMocks(this);

        AbstractBinder binder = new AbstractBinder() {
            @Override
            protected void configure() {
                bind(trackIdInstance).to(TrackIdInstance.class);
                bind(logger).to(Logger.class);
                bind(servletRequest).to(HttpServletRequest.class);
                bind(httpRequestService).to(HttpRequestService.class);
                bind(electionEventTranslationService).to(ElectionEventTranslationService.class);
                bind(electionEventTranslationRepository).to(ElectionEventTranslationRepository.class);

            }
        };
        resource = new ElectionEventResource();
        forceSet(TestProperties.CONTAINER_PORT, "0");
        return new ResourceConfig().register(resource).register(binder).register(new ResourceNotFoundExceptionHandler())
            .register(new ApplicationExceptionHandler());
    }

    private ElectionEventTranslationList getTranslations() {
        ElectionEventTranslationList electionEventTranslationList = new ElectionEventTranslationList();
        ElectionEventTranslation translation = new ElectionEventTranslation();
        translation.setTenantId(tenantId);
        translation.setAlias(alias);
        translation.setElectionEventId(electionEventId);
        electionEventTranslationList.setElectionEventTranslations(Arrays.asList(translation));
        return electionEventTranslationList;
    }

}
