package com.atlassian.stash.internal.web.util;

import com.atlassian.bitbucket.avatar.CacheableAvatarSupplier;
import com.atlassian.bitbucket.i18n.I18nService;
import com.google.common.net.HttpHeaders;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.*;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class AvatarSupportTest {

    private static final String AVATAR_CONTENT_TYPE = "image/png";
    private static final String AVATAR_CONTENT = "content";
    private static final long AVATAR_TIMESTAMP_IN_MS = 42000L;
    public static final int AVATAR_EXPIRY_IN_DAYS = 365;

    @Mock
    private CacheableAvatarSupplier avatarSupplier;
    @Mock
    private I18nService i18nService;

    @InjectMocks
    private AvatarSupport avatarSupport;

    @Before
    public void setUp() throws Exception {
        when(avatarSupplier.getContentType()).thenReturn(AVATAR_CONTENT_TYPE);
        when(avatarSupplier.open()).thenReturn(new ByteArrayInputStream(AVATAR_CONTENT.getBytes()));
        when(avatarSupplier.getTimestamp()).thenReturn(AVATAR_TIMESTAMP_IN_MS);
    }

    @Test
    public void testWithVersionIdParameter() throws Exception {
        // when a versionId parameter is present, we should cache permanently
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.addParameter("v", Long.toString(System.currentTimeMillis()));
        MockHttpServletResponse response = new MockHttpServletResponse();
        avatarSupport.streamAvatar(avatarSupplier, request, response);

        assertNotNull(response.getHeader(HttpHeaders.EXPIRES));
        String cacheControl = response.getHeader(HttpHeaders.CACHE_CONTROL);
        assertNotNull(cacheControl);
        assertTrue(cacheControl.startsWith("private, max-age="));
        assertEquals(AVATAR_EXPIRY_IN_DAYS, TimeUnit.SECONDS.toDays(Long.parseLong(cacheControl.split("=")[1])));
        assertEquals(response.getHeader(HttpHeaders.PRAGMA), "");

    }

    @Test
    public void testWithNullVersionIdParameter() throws Exception {
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.addParameter("v", (String) null);
        MockHttpServletResponse response = new MockHttpServletResponse();
        avatarSupport.streamAvatar(avatarSupplier, request, response);
        assertNull(response.getHeader(HttpHeaders.EXPIRES));
        assertNull(response.getHeader(HttpHeaders.CACHE_CONTROL));
    }

    @Test
    public void testWithEmptyVersionIdParameter() throws Exception {
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.addParameter("v", "");
        MockHttpServletResponse response = new MockHttpServletResponse();
        avatarSupport.streamAvatar(avatarSupplier, request, response);
        assertNull(response.getHeader(HttpHeaders.EXPIRES));
        assertNull(response.getHeader(HttpHeaders.CACHE_CONTROL));
    }


    @Test
    public void testWithoutNoModifiedSinceHeader() throws Exception {
        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
        avatarSupport.streamAvatar(avatarSupplier, request, response);
    }

    @Test
    public void testIfModifiedRecently() throws Exception {
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.addHeader("If-Modified-Since", AVATAR_TIMESTAMP_IN_MS - 2000);
        MockHttpServletResponse response = new MockHttpServletResponse();
        avatarSupport.streamAvatar(avatarSupplier, request, response);
    }

    @Test
    public void testIfNotModifiedRecently() throws Exception {
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.addHeader("If-Modified-Since", AVATAR_TIMESTAMP_IN_MS);
        MockHttpServletResponse response = new MockHttpServletResponse();
        avatarSupport.streamAvatar(avatarSupplier, request, response);

        assertEquals(HttpServletResponse.SC_NOT_MODIFIED, response.getStatus());
        assertArrayEquals(new byte[0], response.getContentAsByteArray());
    }

    private static class AvatarSupport extends com.atlassian.stash.internal.web.util.AvatarSupport {
        public AvatarSupport(I18nService i18nService) {
            super(i18nService);
        }
    }

}