package com.atlassian.bitbucket.mesh.git.cache;

import com.atlassian.bitbucket.mesh.AbstractWiredTest;
import com.atlassian.bitbucket.mesh.config.PackCacheConfig;
import com.atlassian.bitbucket.mesh.repository.Repository;
import com.atlassian.bitbucket.mesh.test.annotation.Repo;
import com.atlassian.util.contentcache.ContentCache;
import com.atlassian.util.contentcache.ContentCacheManager;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;

import java.util.Date;

import static org.mockito.Mockito.*;

public class DefaultPackCacheServiceTest extends AbstractWiredTest {

    private static final long TTL_SEC = 30L;

    @Mock
    private ContentCache cache;
    @Mock
    private ContentCacheManager cacheManager;
    @Mock
    private PackCacheConfig config;
    @Repo
    private Repository repository;
    private DefaultPackCacheService service;

    @Before
    public void setup() {
        when(cacheManager.getCache(anyString())).thenReturn(cache);
        when(config.getTimeToLive()).thenReturn(TTL_SEC);

        service = new DefaultPackCacheService(cacheManager, config);
    }

    @Test
    public void testClear() {
        service.clear();

        verify(cacheManager).clear();
    }

    @Test
    public void testClearEntry() {
        service.clear(repository, "key");

        verify(cacheManager).getCache(getRegion());
        verify(cache).remove("key");
    }

    @Test
    public void testCreateExpiry() {
        long expected = System.currentTimeMillis() + TTL_SEC * 1000L;

        Date expiry = service.createExpiryDate();
        assertNotNull(expiry);

        long actual = expiry.getTime();
        assertTrue(actual >= expected);
        // allow a small error of margin because of small timing differences
        assertTrue((actual - expected) < (TTL_SEC + 5));
    }

    @Test
    public void testClearRepoCache() {
        service.clear(repository);

        verify(cacheManager).getCache(getRegion());
        verify(cache).clear();
    }

    @Test
    public void testGetCacheRegion() {
        assertEquals(getRegion(), DefaultPackCacheService.getCacheRegion(repository));
    }

    @Test
    public void testGetCacheRegionForNullRepo() {
        assertThrows(NullPointerException.class, () -> DefaultPackCacheService.getCacheRegion(null));
    }

    @Test
    public void testGetStatistics() {
        service.getStatistics();

        verify(cacheManager).getStatistics();
    }

    @Test
    public void testGetRepoStatistics() {
        service.getStatistics(repository);

        verify(cacheManager).getCache(getRegion());
        verify(cache).getStatistics();
    }

    private String getRegion() {
        return DefaultPackCacheService.getCacheRegion(repository);
    }
}
