package com.atlassian.stash.internal.scm.git.command.foreachref;

import com.atlassian.bitbucket.repository.Tag;
import com.atlassian.bitbucket.repository.TagCallback;
import com.atlassian.bitbucket.repository.TagContext;
import com.atlassian.bitbucket.repository.TagSummary;
import com.atlassian.bitbucket.scm.CommandResult;
import com.atlassian.bitbucket.scm.CommandSummary;
import com.atlassian.utils.process.Watchdog;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.io.InputStream;

import static com.atlassian.bitbucket.hamcrest.RepositoryMatchers.tag;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class TagCallbackForEachRefOutputHandlerTest {

    @Mock
    private TagCallback callback;

    @Before
    public void setup() throws IOException {
        when(callback.onTag(any(Tag.class))).thenReturn(true);
    }

    @Test
    public void testExecute() throws Exception {
        process("git-for-each-ref-tags.out", null, callback);

        InOrder order = inOrder(callback);
        order.verify(callback).onStart(isA(TagContext.class));
        order.verify(callback).onTag(argThat(tag("v1.7.8.1", "2ce0edcd786b790fed580e7df56291619834d276",
                "a22731114eb6a0291d21e914a10564e70dc3caf6")));
        order.verify(callback).onTag(argThat(tag("v1.7.7.5", "66c11f02b031aca6f1756086fefdf4b8a5575c56",
                "b36dcd72396add3a1e825234ee566db2574fae73")));
        order.verify(callback).onTag(argThat(tag("v1.7.6.5", "15b7898c5e9fc6fed9a6064213cfcd08cf7d7314",
                "8634b0870be3869a4bb36abab55574f9d1e00e78")));
        order.verify(callback).onTag(argThat(tag("gitgui-0.16.0", "942e6baa92846e5628752c65a22bc4957d8de4d0",
                "3da5ebb0ea02d4b777abacbc6f2d077a45975f00")));
        order.verify(callback).onTag(argThat(tag("v1.7.8", "406da7803217998ff6bf5dc69c55b1613556c2f4",
                "8b891d2711bdfb153176cc325150e0233bdff175")));
        order.verify(callback, times(5)).onTag(isA(Tag.class)); // 5 more
        order.verify(callback).onEnd(isA(TagSummary.class));
        verifyNoMoreInteractions(callback);
    }

    @Test
    public void testExecuteWithLightweightTags() throws Exception {
        process("git-for-each-ref-lightweight-tags.out", null, callback);

        InOrder order = inOrder(callback);
        order.verify(callback).onStart(isA(TagContext.class));
        order.verify(callback).onTag(argThat(tag("retagged_signed_tag", "12ebe2a58367347cd39f19f5a72f3cbec7b8f9a9",
                "9b4e781dea0769888fe270e06ad76675f73851b1")));
        order.verify(callback).onTag(argThat(tag("signed_tag", "0a943a29376f2336b78312d99e65da17048951db",
                "12ebe2a58367347cd39f19f5a72f3cbec7b8f9a9")));
        order.verify(callback).onTag(argThat(tag("a", "0a943a29376f2336b78312d99e65da17048951db"))); // Lightweight
        order.verify(callback).onTag(argThat(tag("b", "0a943a29376f2336b78312d99e65da17048951db"))); // Lightweight
        order.verify(callback).onTag(argThat(tag("backdated_annotated_tag", "57150c54c38d6570b2fd5e6d6cfc19476de44e84",
                "80aa5be5ecf39660f798858482254f7a2ae9110e")));
        order.verify(callback).onTag(argThat(tag("c", "8fb8538799b2481750eac52716931d895d029b7c"))); // Lightweight
        order.verify(callback).onEnd(isA(TagSummary.class));
        verifyNoMoreInteractions(callback);
    }

    @Test
    public void testExecuteWithFilterText() throws Exception {
        process("git-for-each-ref-tags.out", "v1.7.8", callback);

        InOrder order = inOrder(callback);
        order.verify(callback).onStart(isA(TagContext.class));
        order.verify(callback).onTag(argThat(tag("v1.7.8.1", "2ce0edcd786b790fed580e7df56291619834d276",
                "a22731114eb6a0291d21e914a10564e70dc3caf6")));
        order.verify(callback).onTag(argThat(tag("v1.7.8", "406da7803217998ff6bf5dc69c55b1613556c2f4",
                "8b891d2711bdfb153176cc325150e0233bdff175")));
        order.verify(callback).onTag(argThat(tag("v1.7.8-rc4", "fc14b89a7e6899b8ac3b5751ec2d8c98203ea4c2",
                "f96a6ecfb81381758dfd9c0dc6951a21c74316ed")));
        order.verify(callback).onTag(argThat(tag("v1.7.8-rc3", "4d2440fe0daa9ad1556dfd220af8b3a883cf849d",
                "a67939439750839d77c69f874a2d0587f7c063ad")));
        order.verify(callback).onTag(argThat(tag("v1.7.8-rc2", "bc1bbe0c19a6ff39522b4fa3259f34150e308e1f",
                "9765e24e023e94e9f38a8220a5efeda848b7c496")));
        order.verify(callback).onEnd(isA(TagSummary.class));
        verifyNoMoreInteractions(callback);
    }

    @Test
    public void testExecuteWithNoResults() throws Exception {
        process("git-for-each-ref-tags.out", "matches nothing", callback);

        InOrder order = inOrder(callback);
        order.verify(callback).onStart(isA(TagContext.class));
        order.verify(callback).onEnd(isA(TagSummary.class));
        verifyNoMoreInteractions(callback);
    }

    private void process(String resource, String filter, TagCallback callback) throws Exception {
        CallbackForEachRefOutputHandler handler = new CallbackForEachRefOutputHandler(
                new ForEachTagCallback(callback, filter));
        handler.setWatchdog(mock(Watchdog.class));

        try (InputStream is = new ClassPathResource(resource, getClass()).getInputStream()) {
            handler.process(is);
        }
        handler.onComplete(new CommandSummary.Builder(CommandResult.SUCCEEDED).build());
    }
}
