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

import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.scytl.products.ov.commons.infrastructure.health.HealthCheckValidationType;
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.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;

import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import com.scytl.products.ov.commons.infrastructure.health.HealthCheck;
import com.scytl.products.ov.commons.infrastructure.health.HealthCheckRegistry;
import com.scytl.products.ov.commons.infrastructure.health.HealthCheckStatus;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class CheckHealthResourceTest extends JerseyTest {

    @Mock
    HealthCheckRegistry healthCheckRegistry;

    private CheckHealthResource sut;

    @Override
    protected Application configure() {
        forceSet(TestProperties.CONTAINER_PORT, "0"); // allow parallel testing

        MockitoAnnotations.initMocks(this);

        // injection
        AbstractBinder binder = new AbstractBinder() {
            @Override
            protected void configure() {
                bind(healthCheckRegistry).to(HealthCheckRegistry.class);
            }
        };
        sut = new CheckHealthResource();
        return new ResourceConfig().register(sut) // our controller
            .register(binder) // injection support
            .register(JacksonJsonProvider.class); // json writer
    }

    @Test
    public void whenHealthChecksAreHealthyShouldReturnOK() {
        // given
        HashMap<HealthCheckValidationType, HealthCheck.HealthCheckResult> healthCheckResults = new HashMap<>();
        healthCheckResults.put(HealthCheckValidationType.DATABASE, HealthCheck.HealthCheckResult.healthy());
        HealthCheckStatus status = new HealthCheckStatus(healthCheckResults);
        when(healthCheckRegistry.runAllChecks()).thenReturn(status);

        // when
        final Response response = target("check").request().accept(MediaType.APPLICATION_JSON_TYPE).get();

        // then
        Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
    }

    @Test
    public void whenHealthAnyCheckIsUnHealthyShouldReturnServiceUnavailable() {
        // given
        HashMap<HealthCheckValidationType, HealthCheck.HealthCheckResult> healthCheckResults = new HashMap<>();
        healthCheckResults.put(HealthCheckValidationType.DATABASE, HealthCheck.HealthCheckResult.healthy());
        healthCheckResults.put(HealthCheckValidationType.LOGGING_INITIALIZED,
            HealthCheck.HealthCheckResult.unhealthy("unhealthy check"));
        HealthCheckStatus status = new HealthCheckStatus(healthCheckResults);
        when(healthCheckRegistry.runAllChecks()).thenReturn(status);

        // when
        final Response response = target("check").request().accept(MediaType.APPLICATION_JSON_TYPE).get();

        // then
        Assert.assertEquals(Response.Status.SERVICE_UNAVAILABLE.getStatusCode(), response.getStatus());
    }


    @Test
    public void testIfServiceRunning() {
        //given
        HashMap<HealthCheckValidationType, HealthCheck.HealthCheckResult> healthCheckResults = new HashMap<>();
        healthCheckResults.put(HealthCheckValidationType.DATABASE, HealthCheck.HealthCheckResult.healthy());
        HealthCheckStatus status = new HealthCheckStatus(healthCheckResults);
        List<HealthCheckValidationType> validationsToSkip = Arrays.asList(HealthCheckValidationType.LOGGING_INITIALIZED);
        when(healthCheckRegistry.runChecksDifferentFrom(validationsToSkip)).thenReturn(status);

        //when
        final Response response = target("check").path("ready").request().accept(MediaType.APPLICATION_JSON_TYPE).get();

        //then
        Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
    }



}
