package com.atlassian.stash.internal.server.analytics;

import com.atlassian.fugue.Option;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.io.IOException;
import java.net.URI;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class DefaultAwsAnalyticsFactoryTest {

    @Mock
    private HttpClient client;
    private DefaultAwsAnalyticsFactory awsAnalyticsFactory;

    @Before
    public void setUp() throws Exception {
        awsAnalyticsFactory = new DefaultAwsAnalyticsFactory(client);
    }

    @Test
    public void testCreateShouldFailIfConnectionToAmazonFails() throws Exception {
        when(client.execute(any(HttpGet.class))).thenThrow(new IOException());
        assertTrue(awsAnalyticsFactory.create().isEmpty());
    }

    @Test
    public void testCreate() throws Exception {
        String amiHex = "2bb65342";
        mockRequest(DefaultAwsAnalyticsFactory.AWS_AMI_ID_URI, "ami-" + amiHex);
        mockRequest(DefaultAwsAnalyticsFactory.AWS_INSTANCE_TYPE_URI, "c4.2xlarge");

        Option<AwsAnalytics> awsAnalyticsOption = awsAnalyticsFactory.create();
        assertTrue(awsAnalyticsOption.isDefined());
        assertEquals("ami-" + Integer.parseInt(amiHex, 16), awsAnalyticsOption.get().getAmiId());
        assertEquals("c4.2xlarge", awsAnalyticsOption.get().getInstanceType());
    }

    @Test
    public void testCreateShouldFailIfStashIsNotInAws() throws Exception {
        when(client.execute(any(HttpGet.class))).thenThrow(new IOException("Unreachable"));
        Option<AwsAnalytics> awsAnalyticsOption = awsAnalyticsFactory.create();
        assertFalse(awsAnalyticsOption.isDefined());
    }

    private void mockRequest(URI uri, String responseString) throws IOException {
        HttpResponse instanceResponse = mock(HttpResponse.class);
        HttpEntity instanceEntity = mock(HttpEntity.class);
        when(instanceResponse.getEntity()).thenReturn(instanceEntity);
        when(instanceEntity.getContent()).thenReturn(IOUtils.toInputStream(responseString));
        doReturn(instanceResponse).when(client).execute(argThat(new IsHttpGet(uri)));
    }

    private class IsHttpGet extends ArgumentMatcher<HttpGet> {

        private final URI url;

        public IsHttpGet(URI url) {
            this.url = url;
        }

        public boolean matches(Object httpGet) {
            return ((HttpGet) httpGet).getURI().equals(url);
        }
    }

}