package com.atlassian.stash.internal.pull.comment.drift;

import com.atlassian.bitbucket.annotation.Dao;
import com.atlassian.bitbucket.annotation.DataSet;
import com.atlassian.stash.internal.AbstractDaoTest;
import com.atlassian.stash.internal.DataSets;
import com.atlassian.stash.internal.pull.HibernatePullRequestDao;
import com.atlassian.stash.internal.pull.InternalPullRequest;
import com.atlassian.stash.internal.pull.PullRequestDao;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.hamcrest.Matchers.hasSize;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@DataSet({DataSets.PROJECTS, DataSets.REPOSITORIES, DataSets.USERS, DataSets.PULL_REQUESTS, DataSets.DRIFT_REQUESTS})
public class HibernateCommentDriftRequestDaoTest extends AbstractDaoTest {

    @Dao(HibernatePullRequestDao.class)
    private PullRequestDao pullRequestDao;

    @Dao
    private HibernateCommentDriftRequestDao dao;

    @Test
    public void testCreate() {
        InternalPullRequest pullRequest = pullRequestDao.getById(1L);
        InternalDriftRequest request = new InternalDriftRequest(null, pullRequest,
                "fd0b1ede3195ab2df5b4ed35f4085472e49d69d6", "ea98ae6dcc4dbee222bcd9ed1a638ac83f38ddea",
                "2e6776b828fc08bd45f43d7c1b7ff34f6a36db04", "d1935819423d7557d19934e2591e60636391411b");

        InternalDriftRequest saved = dao.create(request);
        assertNotNull(saved);

        flush();
        evict(saved, saved.getId());

        InternalDriftRequest retrieved = dao.getById(saved.getId());
        assertNotNull(retrieved);
        assertEquals(saved.getId(), retrieved.getId());
        assertEquals(request.getOldFromHash(), retrieved.getOldFromHash());
        assertEquals(request.getOldToHash(), retrieved.getOldToHash());
        assertEquals(request.getNewFromHash(), retrieved.getNewFromHash());
        assertEquals(request.getNewToHash(), retrieved.getNewToHash());
        assertEquals(request.getPullRequest().getGlobalId(), retrieved.getPullRequest().getGlobalId());
    }

    @Test
    public void testDeleteAllEmptyList() {
        dao.deleteAll(Collections.emptyList());

        flush();

        assertEquals(2, dao.findAll().size());
    }

    @Test
    public void testDeleteAllIgnoresTransientRequests() {
        InternalDriftRequest transientRequest = mock(InternalDriftRequest.class);
        when(transientRequest.getId()).thenReturn(null);

        dao.deleteAll(Arrays.asList(dao.getById(1L), transientRequest));

        flush();
        clear();

        assertNull(dao.getById(1L));
    }

    @Test
    public void testDeleteAllMultiple() {
        List<InternalDriftRequest> requests = dao.findAll();

        dao.deleteAll(requests);

        flush();
        clear();

        assertNull(dao.getById(1L));
        assertNull(dao.getById(2L));
        assertEquals(0, dao.findAll().size());
    }

    @Test
    public void testDeleteAllSingleRequest() {
        InternalDriftRequest request = dao.getById(2L);
        dao.deleteAll(Collections.singletonList(request));

        flush();
        clear();

        assertNull(dao.getById(2L));
        assertNotNull(dao.getById(1L));
    }

    @Test
    public void testFindByGlobalId() {
        List<InternalDriftRequest> requests = dao.findByGlobalId(1L);

        assertThat(requests, hasSize(2));
        assertEquals("b4b850f01df7ebdf11dc24a6ee2002b4666a9c09", requests.get(0).getOldFromHash());
        assertEquals("b44f0d88936bba115be35db792dcf4051531b881", requests.get(1).getOldFromHash());

        requests = dao.findByGlobalId(2L);
        assertThat(requests, hasSize(0));
    }

    @Test
    public void testFindPendingPullRequests() {
        List<InternalPullRequest> pullRequests = dao.findPendingPullRequests(0); //>= 0, should return rows
        assertThat(pullRequests, hasSize(1));
        assertEquals(1L, pullRequests.get(0).getGlobalId());

        // This will not be used this way at runtime, but it's the simplest way to test the functionality
        // with the existing test data
        pullRequests = dao.findPendingPullRequests(-1); //< 0 should return empty
        assertNotNull(pullRequests);
        assertTrue(pullRequests.isEmpty());
    }

    public void testFindAll() {
        List<InternalDriftRequest> requests = dao.findAll();

        assertEquals(2, requests.size());
        assertEquals("b4b850f01df7ebdf11dc24a6ee2002b4666a9c09", requests.get(0).getOldFromHash());
        assertEquals("b44f0d88936bba115be35db792dcf4051531b881", requests.get(1).getOldFromHash());
    }

    @Test
    public void testGetById() {
        InternalDriftRequest request = dao.getById(1L);

        assertNotNull(request);
        assertEquals("b4b850f01df7ebdf11dc24a6ee2002b4666a9c09", request.getOldFromHash());
    }

    @Test
    public void testGetByIdNonExisting() {
        assertNull(dao.getById(99L));
    }

    @SuppressWarnings("ConstantConditions")
    @Test
    public void testUpdateAttempts() {
        assertEquals(0, dao.getById(1L).getAttempts());
        assertEquals(0, dao.getById(2L).getAttempts());

        InternalDriftRequest request = dao.getById(1L);
        dao.updateAttempts(request, 5);

        assertEquals(5, dao.getById(1L).getAttempts());
        assertEquals(0, dao.getById(2L).getAttempts());
    }
}
