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

import java.util.Optional;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;

import com.scytl.products.ov.kt.domain.model.ballotbox.BallotBoxTranslationList;
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.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.ballotbox.BallotBoxTranslation;
import com.scytl.products.ov.kt.services.BallotBoxTranslationService;

/**
 * Test class for the endpoint of the BallotBoxResource class
 */
public class BallotBoxResourceTest 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";

    public static final int BAD_REQUEST = 400;
    public static final String ballotBoxId = "100";

    @Mock
    private HttpServletRequest servletRequest;

    @Mock
    private Logger logger;

    @Mock
    private TrackIdInstance trackIdInstance;

    @Mock
    private HttpRequestService httpRequestService;

    @Mock
    private BallotBoxTranslationService ballotBoxTranslationService;

    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/ballotbox/tenant/{tenantId}/electionevent/{electionEventId}/alias/{alias}";

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

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

    private BallotBoxResource resource;

    @Test
    public void getByAliasOk() {

        int expectedStatus = OK;

        BallotBoxTranslation translation = new BallotBoxTranslation();

        commonPreparation();

        when(ballotBoxTranslationService.findByAlias(anyString(), anyString(), anyString()))
            .thenReturn(Optional.of(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 {

        int expectedStatus = NOT_FOUND;

        commonPreparation();

        when(ballotBoxTranslationService.findByAlias(anyString(), anyString(), anyString()))
            .thenReturn(Optional.empty());

        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() {

        int expectedStatus = OK;

        BallotBoxTranslation translation = new BallotBoxTranslation();

        commonPreparation();

        when(ballotBoxTranslationService.findByBallotBoxId(anyString(), anyString(), anyString()))
            .thenReturn(Optional.of(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(ballotBoxTranslationService.findByBallotBoxId(anyString(), anyString(), anyString()))
            .thenReturn(Optional.empty());

        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 uploadTranslationsBadRequest() throws IllegalArgumentException {
        int expectedStatus = BAD_REQUEST;

        BallotBoxTranslationList ballotBoxTranslationList = getBallotBoxTranslationList();
        doThrow(new IllegalArgumentException()).when(ballotBoxTranslationService).saveOrUpdate(anyString(), any());

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

    @Test
    public void uploadTranslations() throws IllegalArgumentException {

        int expectedStatus = OK;

        BallotBoxTranslationList ballotBoxTranslationList = getBallotBoxTranslationList();
        doNothing().when(ballotBoxTranslationService).saveOrUpdate(anyString(), any());


        int status = target(PATH_POST).resolveTemplate(TENANT_ID, tenantId).request()
                .post(Entity.entity(ballotBoxTranslationList, 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(ballotBoxTranslationService).to(BallotBoxTranslationService.class);

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


    private BallotBoxTranslationList getBallotBoxTranslationList() {
        BallotBoxTranslationList ballotBoxTranslationList = new BallotBoxTranslationList();
        BallotBoxTranslation translation = new BallotBoxTranslation();
        translation.setTenantId(tenantId);
        translation.setAlias(alias);
        translation.setBallotBoxId(ballotBoxId);
        translation.setElectionEventId(electionEventId);
        return ballotBoxTranslationList;
    }
}
