package com.atlassian.bitbucket.mesh.repository;

import com.atlassian.bitbucket.mesh.AbstractDaoTest;
import com.atlassian.bitbucket.mesh.dbunit.DataSet;
import com.atlassian.bitbucket.mesh.dbunit.DataSets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Map;

import static org.junit.Assert.*;

@DataSet(DataSets.REPOSITORY_ATTRIBUTES)
public class JdbcRepositoryAttributeDaoTest extends AbstractDaoTest {

    @Resource
    private RepositoryAttributeDao dao;

    @Test
    public void testGetContentHash() {
        assertNull(dao.getContentHash("no-hashes-id"));
        assertNull(dao.getContentHash("only-defaults-id"));
        assertNull(dao.getContentHash("no-such-repository"));
        assertEquals(StringUtils.repeat('A', 64), dao.getContentHash("has-hashes-id"));
    }

    @Test
    public void testGetMetadataHash() {
        assertNull(dao.getMetadataHash("no-hashes-id"));
        assertNull(dao.getMetadataHash("only-defaults-id"));
        assertNull(dao.getMetadataHash("no-such-repository"));
        assertEquals(StringUtils.repeat('B', 64), dao.getMetadataHash("has-hashes-id"));
    }

    @Test
    public void testGetVersion() {
        assertEquals(1L, dao.getVersion("no-such-repository"));
        assertEquals(1L, dao.getVersion("only-defaults-id"));
        assertEquals(3L, dao.getVersion("version-id"));
    }

    @DataSet(DataSets.MANAGED_REPOSITORY_ATTRIBUTES)
    @Test
    public void testGetVersionsByPartitions() {
        Map<String, Long> result = dao.getVersionsByPartitions(ImmutableSet.of());
        assertEquals(ImmutableMap.of(
                "p/0018/h/0f71ffc5121881a26d05/r/45", 2L,
                "p/0018/h/f551c0701acb9ab40e19/r/9", 113L,
                "p/00b4/h/91dfea40be2db256aee9/r/311", 92L,
                "p/00b4/h/91dfea40be2db256aee9/r/319", 7L,
                "p/00b4/h/ce9e8bcac05c8b9286b2/r/12", 1841L
        ), result);
    }

    @DataSet(DataSets.MANAGED_REPOSITORY_ATTRIBUTES)
    @Test
    public void testGetVersionsByPartitionsNoMatches() {
        Map<String, Long> result = dao.getVersionsByPartitions(ImmutableSet.of("0000", "0001", "0002", "0003"));
        assertTrue(result.isEmpty());
    }

    @Test
    public void testGetVersionsByPartitionsNonManagedRepositories() {
        Map<String, Long> result = dao.getVersionsByPartitions(ImmutableSet.of());
        assertTrue(result.isEmpty());
    }

    @DataSet(DataSets.MANAGED_REPOSITORY_ATTRIBUTES)
    @Test
    public void testGetVersionsByPartitionsWithPartitions() {
        Map<String, Long> result = dao.getVersionsByPartitions(ImmutableSet.of("0010", "0018"));
        assertEquals(ImmutableMap.of(
                "p/0018/h/0f71ffc5121881a26d05/r/45", 2L,
                "p/0018/h/f551c0701acb9ab40e19/r/9", 113L
        ), result);
    }

    @Test
    public void testIncrementAndGetVersionForInsert() {
        assertEquals(2L, dao.incrementAndGetVersion("unmapped-id"));
        assertEquals(2L, dao.getVersion("unmapped-id"));
    }

    @Test
    public void testIncrementAndGetVersionForUpdate() {
        assertEquals(3L, dao.getVersion("version-id"));
        assertEquals(4L, dao.incrementAndGetVersion("version-id"));
        assertEquals(4L, dao.getVersion("version-id"));
    }

    @Test
    public void testIsReadOnly() {
        assertTrue(dao.isReadOnly("read-only-id"));
        assertFalse(dao.isReadOnly("read-write-id"));
    }

    @Test
    public void testIsReadOnlyForNonexistentId() {
        assertFalse(dao.isReadOnly("nonexistent-id"));
    }

    @Test
    public void testReplaceEmpty() {
        dao.replaceReadOnly(Collections.emptyList());
        assertFalse(dao.isReadOnly("read-only-id"));
        assertFalse(dao.isReadOnly("read-write-id"));
    }

    @Test
    public void testReplaceReadOnly() {
        dao.replaceReadOnly(ImmutableList.of("a", "b"));
        assertTrue(dao.isReadOnly("a"));
        assertTrue(dao.isReadOnly("b"));
        assertFalse(dao.isReadOnly("read-only-id"));
        assertFalse(dao.isReadOnly("read-write-id"));
    }

    @Test
    public void testSetContentHashForInsert() {
        String repositoryId = "new-repository-for-set-content-hash";
        String hash = StringUtils.repeat("W", 64);
        dao.setContentHash(repositoryId, hash);
        assertEquals(hash, dao.getContentHash(repositoryId));
    }

    @Test
    public void testSetContentHashForUpdate() {
        String repositoryId = "no-content-hash-id";
        String hash = StringUtils.repeat("X", 64);
        dao.setContentHash(repositoryId, hash);
        assertEquals(hash, dao.getContentHash(repositoryId));
    }

    @Test
    public void testSetMetadataHashForInsert() {
        String repositoryId = "new-repository-for-set-metadata-hash";
        String hash = StringUtils.repeat("Y", 64);
        dao.setMetadataHash(repositoryId, hash);
        assertEquals(hash, dao.getMetadataHash(repositoryId));
    }

    @Test
    public void testSetMetadataHashForUpdate() {
        String repositoryId = "no-content-hash-id";
        String hash = StringUtils.repeat("Z", 64);
        dao.setMetadataHash(repositoryId, hash);
        assertEquals(hash, dao.getMetadataHash(repositoryId));
    }

    @Test
    public void testSetReadOnlyForInsert() {
        dao.setReadOnly("new-unmapped-id", true);
        assertTrue(dao.isReadOnly("new-unmapped-id"));
    }

    @Test
    public void testSetReadOnlyForUpdate() {
        dao.setReadOnly("read-only-id", false);
        assertFalse(dao.isReadOnly("read-only-id"));
    }

    @Test
    public void testSetVersionForInsert() {
        dao.setVersion("new-unmapped-id", 7L);
        assertEquals(7L, dao.getVersion("new-unmapped-id"));
    }

    @Test
    public void testSetVersionForUpdate() {
        assertEquals(3L, dao.getVersion("version-id"));
        dao.setVersion("version-id", 2L);
        assertEquals(2L, dao.getVersion("version-id"));
    }
}
