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

import com.atlassian.bitbucket.mesh.AbstractWiredTest;
import com.atlassian.bitbucket.mesh.event.EventPublisher;
import com.atlassian.bitbucket.mesh.git.builder.GitProcessBuilderFactory;
import com.atlassian.bitbucket.mesh.repository.Repository;
import com.atlassian.bitbucket.mesh.repository.TranscodeDiffSettingChangedEvent;
import com.atlassian.bitbucket.mesh.test.annotation.DirtiesRepo;
import com.atlassian.bitbucket.mesh.test.annotation.Repo;
import com.atlassian.bitbucket.mesh.transaction.StubTransactionManager;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;

public class DefaultTranscodeServiceTest extends AbstractWiredTest {

    @Rule
    public final StubTransactionManager transactionManager = new StubTransactionManager();

    @Autowired
    private GitProcessBuilderFactory builderFactory;
    @Mock
    private EventPublisher eventPublisher;
    @Repo
    private Repository repository;
    private DefaultTranscodeService service;

    @Before
    public void setup() {
        service = new DefaultTranscodeService(builderFactory, eventPublisher, transactionManager);
    }

    @Test
    public void testIsEnabled() {
        assertFalse(service.isEnabled(repository));
    }

    @DirtiesRepo
    @Test
    public void testSetEnabled() {
        ArgumentCaptor<TranscodeDiffSettingChangedEvent> captor = ArgumentCaptor.forClass(TranscodeDiffSettingChangedEvent.class);
        service.setEnabled(repository, true);
        assertTrue(service.isEnabled(repository));
        transactionManager.assertTransactions(1, 0);

        service.setEnabled(repository, false);
        assertFalse(service.isEnabled(repository));
        transactionManager.assertTransactions(2, 0);
        verify(eventPublisher, times(2)).publish(captor.capture());
        List<TranscodeDiffSettingChangedEvent> events = captor.getAllValues();
        assertTrue(events.get(0).isEnabled());
        assertFalse(events.get(1).isEnabled());
    }

    @Test
    public void setEnabledThrowsWhenTransactionRollsBack() {
        transactionManager.stubCoordinatorVote(false);

        assertThrows(EnableTranscodeFailedException.class, () -> service.setEnabled(repository, true));
        assertFalse(service.isEnabled(repository));
        transactionManager.assertTransactions(0, 1);
        verifyNoInteractions(eventPublisher);
    }

    @DirtiesRepo
    @Test
    public void testSetEnabledToFalseWhenDisabled() {
        service.setEnabled(repository, false);
        assertFalse(service.isEnabled(repository));
        transactionManager.assertTransactions(1, 0);
        verifyNoInteractions(eventPublisher);
    }

    @DirtiesRepo
    @Test
    public void testSetEnabledTwice() {
        service.setEnabled(repository, true);
        service.setEnabled(repository, true);
        assertTrue(service.isEnabled(repository));

        transactionManager.assertTransactions(2, 0);
    }
}