package com.geekbeast.rhizome.tests.bootstrap;

import java.io.IOException;

import javax.ws.rs.core.MediaType;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;

import com.dataloom.client.LoomByteConverterFactory;
import com.dataloom.client.LoomCallAdapterFactory;
import com.dataloom.client.LoomJacksonConverterFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.geekbeast.rhizome.tests.configurations.TestConfiguration;
import com.geekbeast.rhizome.tests.controllers.SimpleControllerAPI;
import com.geekbeast.rhizome.tests.pods.DispatcherServletsPod;
import com.google.common.base.Optional;
import com.google.common.net.HttpHeaders;
import com.kryptnostic.rhizome.core.Rhizome;
import com.kryptnostic.rhizome.pods.hazelcast.RegistryBasedHazelcastInstanceConfigurationPod;

import digital.loom.rhizome.authentication.Auth0SecurityTestPod;
import digital.loom.rhizome.authentication.Auth0TestPod;
import digital.loom.rhizome.authentication.AuthenticationTest;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import retrofit2.Retrofit;

public class RhizomeTests {
    private final static Logger      logger     = LoggerFactory.getLogger( RhizomeTests.class );
    private static Retrofit          adapter;
    public static final byte[]       TEST_BYTES = RandomUtils.nextBytes( 1 << 12 );

    private static Rhizome           rhizome    = null;
    private static TestConfiguration expected   = null;

    @BeforeClass
    public static void plant() throws Exception {
        final String jwtToken = AuthenticationTest.authenticate().getLeft().getIdToken();
        rhizome = new Rhizome(
                Auth0TestPod.class,
                Auth0SecurityTestPod.class,
                DispatcherServletsPod.class,
                RegistryBasedHazelcastInstanceConfigurationPod.class );
        rhizome.sprout();
        logger.info( "Successfully started Rhizome microservice." );
        /*
         * These interceptor are finicky and order dependent. Jetty doesn't do gzip unless content is long enough so
         * only verify gzip is enabled if contentLength > 2K. Exact value is tough since it is post compression.
         */
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .addInterceptor( chain -> {
                    Response response = chain.proceed( chain.request() );// .newBuilder().addHeader(
                                                                         // HttpHeaders.ACCEPT_ENCODING, "gzip, deflate"
                                                                         // ).build() );
                    int responseCode = response.code();
                    if ( responseCode >= 200 && responseCode < 300 && response.body().contentLength() > 2048 ) {
                        Assert.assertTrue( "Content encoding header must be present",
                                response.headers().names().contains( HttpHeaders.CONTENT_ENCODING ) );
                        Assert.assertEquals( "gzip", response.headers().get( HttpHeaders.CONTENT_ENCODING ) );
                    }
                    return response;
                } )
                .addInterceptor( chain -> {
                    Response response = chain.proceed( chain.request() );
                    if ( response.code() == HttpStatus.I_AM_A_TEAPOT.value() ) {
                        Assert.assertTrue( StringUtils.startsWith( response.body().contentType().toString(),
                                MediaType.TEXT_PLAIN ) );
                        return response.newBuilder().code( 200 ).build();
                    }
                    return response;
                } )
                .addInterceptor( chain -> chain
                        .proceed( chain.request().newBuilder().addHeader( "Authorization", "Bearer " + jwtToken )
                                .build() ) )
                .build();
        adapter = new Retrofit.Builder().baseUrl( "http://localhost:8081/rhizome/api/" ).client( httpClient )
                .addConverterFactory( new LoomByteConverterFactory() )
                .addConverterFactory( new LoomJacksonConverterFactory() )
                .addCallAdapterFactory( new LoomCallAdapterFactory() ).build();

        SimpleControllerAPI api = adapter.create( SimpleControllerAPI.class );

        TestConfiguration configuration = api.getTestConfiguration();
        Assert.assertNull( configuration );
        expected = new TestConfiguration(
                RandomStringUtils.random( 10 ),
                Optional.<String> absent() );
        TestConfiguration actual = api.setTestConfiguration( expected );
        Assert.assertEquals( expected, actual );
    }

    @Test
    public void testReadWriteConfiguration() {
        // We're assuming that data is not persisted across runs here.
        SimpleControllerAPI api = adapter.create( SimpleControllerAPI.class );
        TestConfiguration actual = api.getTestConfiguration();
        Assert.assertEquals( expected, actual );
    }

    @Test
    public void testByteArray() throws IOException {
        SimpleControllerAPI api = adapter.create( SimpleControllerAPI.class );

        byte[] response = api.gzipTest();

        Assert.assertNotNull( response );
        Assert.assertArrayEquals( TEST_BYTES, response );
    }

    @Test
    public void teapotTest() throws IOException {
        SimpleControllerAPI api = adapter.create( SimpleControllerAPI.class );
        Assert.assertEquals( "I AM A TEAPOT!", api.teapot() );
    }

    @Test
    public void testSimpleControllerGets() throws Exception {
        SimpleControllerAPI api = adapter.create( SimpleControllerAPI.class );
        ObjectMapper mapper = new ObjectMapper();
        logger.info( "Context configuration: {}", mapper.writeValueAsString( api.getContextConfiguration() ) );
        logger.info( "Jetty configuration: {}", mapper.writeValueAsString( api.getJettyConfiguration() ) );
    }

    @Test
    public void testGetAdminEndpoint() {
        SimpleControllerAPI api = adapter.create( SimpleControllerAPI.class );
        TestConfiguration actual = api.getTestConfigurationSecuredAdmin();
    }

    @Test
    public void testGetFooEndpoint() {
        SimpleControllerAPI api = adapter.create( SimpleControllerAPI.class );
        TestConfiguration actual = api.getTestConfigurationSecuredFoo();
        Assert.assertNull( actual );
    }

    @Test
    public void testGetUserEndpoint() {
        SimpleControllerAPI api = adapter.create( SimpleControllerAPI.class );
        TestConfiguration actual = api.getTestConfigurationSecuredUser();

        Assert.assertEquals( expected, actual );
    }

    @AfterClass
    public static void plow() throws BeansException, Exception {
        logger.info( "Finished testing loading servlet pod." );
        rhizome.wilt();
        logger.info( "Successfully shutdown Jetty, exiting main thread" );
    }
}

@@ -507,74 +507,8 @@
 tus;
-%0Aimport org.springframework.security.access.AccessDeniedException;
 %0A%0Aim
@@ -2687,245 +2687,8 @@
 st()
- );// .newBuilder().addHeader(%0A                                                                         // HttpHeaders.ACCEPT_ENCODING, %22gzip, deflate%22%0A                                                                         // ).build()
  );%0A

Clean up comments