package com.atlassian.bitbucket.internal.mirroring.upstream.rest;

import com.atlassian.bitbucket.AuthorisationException;
import com.atlassian.bitbucket.i18n.KeyedMessage;
import com.atlassian.bitbucket.internal.mirroring.upstream.InternalMirrorServer;
import com.atlassian.bitbucket.internal.mirroring.upstream.InternalMirrorService;
import com.atlassian.bitbucket.permission.Permission;
import com.atlassian.bitbucket.permission.PermissionValidationService;
import com.atlassian.bitbucket.server.ApplicationMode;
import com.atlassian.bitbucket.server.ApplicationModeSupplier;
import com.atlassian.plugin.web.WebInterfaceManager;
import com.atlassian.plugin.web.descriptors.WebPanelModuleDescriptor;
import com.atlassian.plugin.web.model.WebPanel;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import java.util.Arrays;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;

public class WebPanelResourceTest {
    @Rule
    public MockitoRule rule = MockitoJUnit.rule();
    @Mock
    private ApplicationModeSupplier supplier;
    @Mock
    private InternalMirrorService service;
    @Mock
    private PermissionValidationService permissionValidationService;
    @Mock
    private WebInterfaceManager webInterfaceManager;
    @InjectMocks
    private WebPanelResource webPanelResource;

    @Before
    public void before() {
        when(supplier.getMode()).thenReturn(ApplicationMode.DEFAULT);
    }

    @Test
    public void testGetReturns404WhenInMirrorMode() {
        when(supplier.getMode()).thenReturn(ApplicationMode.MIRROR);

        Response response = webPanelResource.get(null);
        assertThat(response.getStatus(), equalTo(Status.NOT_FOUND.getStatusCode()));
        assertThat(response.getEntity(), nullValue());
        assertNoCache(response);
    }

    @Test(expected = AuthorisationException.class)
    public void testGetThrowsErrorIfNotAdmin() {
        doThrow(new AuthorisationException(getKeyedMessage()))
                .when(permissionValidationService).validateForGlobal(Permission.ADMIN);

        webPanelResource.get("null");
    }

    @Test
    public void testGetReturns404WhenMirrorDoesntExist() {
        String id = "id";
        when(service.getById(id)).thenReturn(null);


        Response response = webPanelResource.get(null);
        assertThat(response.getStatus(), equalTo(Status.NOT_FOUND.getStatusCode()));
        assertThat(response.getEntity(), nullValue());
        assertNoCache(response);
    }

    @Test
    public void testGetReturns404WhenWebPanelDoesntExist() {
        String id = "id";
        String addonKey = "addonKey";

        withMirror(id, addonKey).withPanels(panel("one", "one"), panel("two", "two"));

        Response response = webPanelResource.get(id);
        assertThat(response.getStatus(), equalTo(Status.NOT_FOUND.getStatusCode()));
        assertThat(response.getEntity(), nullValue());
        assertNoCache(response);
    }

    @Test
    public void testGetReturnsHtmlWhenWebPanelExists() {
        String id = "id";
        String addonKey = "addonKey";
        String html = "moduleHtml";

        withMirror(id, addonKey).withPanels(panel("one", "one"), panel("addonKey" + "ignoreMe", html));

        Response response = webPanelResource.get(id);
        assertThat(response.getStatus(), equalTo(Status.OK.getStatusCode()));
        assertThat(response.getEntity(), equalTo(html));
        assertNoCache(response);
    }

    private WebPanelResourceTest withMirror(String id, String addonKey) {
        InternalMirrorServer mock = Mockito.mock(InternalMirrorServer.class);
        when(mock.getId()).thenReturn(id);
        when(mock.getAddonKey()).thenReturn(addonKey);

        when(service.getById(id)).thenReturn(mock);

        return this;
    }

    private WebPanelModuleDescriptor panel(String addonKey, String html) {
        WebPanel panel = Mockito.mock(WebPanel.class);
        when(panel.getHtml(Mockito.any())).thenReturn(html);

        WebPanelModuleDescriptor descriptor = Mockito.mock(WebPanelModuleDescriptor.class);
        when(descriptor.getKey()).thenReturn(addonKey);
        when(descriptor.getModule()).thenReturn(panel);

        return descriptor;
    }

    private WebPanelResourceTest withPanels(WebPanelModuleDescriptor... descriptor) {
        when(webInterfaceManager.getWebPanelDescriptors("bitbucket.internal.mirror.config"))
                .thenReturn(Arrays.asList(descriptor));

        return this;
    }

    private KeyedMessage getKeyedMessage() {
        return new KeyedMessage("msg", "msg", "msg");
    }

    private static void assertNoCache(Response response) {
        CacheControl control = (CacheControl) response.getMetadata().getFirst("Cache-Control");
        assertThat(control.isNoCache(), is(true));
    }
}