package com.atlassian.stash.internal.notification.pull.activity;

import com.atlassian.bitbucket.comment.Comment;
import com.atlassian.bitbucket.comment.DiffCommentAnchor;
import com.atlassian.bitbucket.content.DiffSegmentType;
import com.atlassian.bitbucket.pull.PullRequestCommentAnchorDiffType;
import com.atlassian.bitbucket.pull.PullRequestDiffCommentAnchor;
import com.google.common.collect.Iterables;
import org.junit.Before;
import org.junit.Test;

import java.util.Date;
import java.util.List;
import java.util.Map;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class BatchEmailActivityFileTest {

    private static final String FILE = "file";
    private static final String FROM_HASH = "since";
    private static final String FULL_PATH = "path/to/" + FILE;
    private static final String PATH = "path/to/";
    private static final String TO_HASH = "until";

    private BatchEmailActivityFile file;

    @Before
    public void setup() {
        PullRequestDiffCommentAnchor anchor = mock(PullRequestDiffCommentAnchor.class);
        when(anchor.getPath()).thenReturn(FULL_PATH);
        when(anchor.getFromHash()).thenReturn(FROM_HASH);
        when(anchor.getToHash()).thenReturn(TO_HASH);
        when(anchor.getDiffType()).thenReturn(PullRequestCommentAnchorDiffType.COMMIT);
        file = new BatchEmailActivityFile(anchor);
    }

    @Test
    public void testLineComment() throws Exception {
        CommentThread commentThread = commentThread(0);
        file.getCommentThreadCollection(new DiffAnchorInfo(1, 2, DiffSegmentType.CONTEXT, "line"))
                .add(commentThread);

        Map<String, Object> data = file.asData();

        assertThat(data, hasEntry("path", (Object) PATH));
        assertThat(data, hasEntry("name", (Object) FILE));
        assertThat(data, hasEntry("fromHash", FROM_HASH));
        assertThat(data, hasEntry("toHash", TO_HASH));
        assertThat(data, hasEntry("date", (Object) commentThread.getDate()));

        List<BatchEmailActivityFile.FileLineData> lines = getLines(data);
        assertThat(lines, hasSize(1));
        BatchEmailActivityFile.FileLineData line = Iterables.getOnlyElement(lines);
        assertThat(line.getText(), is("line"));
        assertThat(line.getLine(), is(1));
        assertThat(line.getType(), is(DiffSegmentType.CONTEXT));
        assertThat(line.getThreads(), contains(commentThread));
    }

    @Test
    public void testFileComment() throws Exception {
        CommentThread commentThread = commentThread(0);
        file.getCommentThreadCollection(new DiffAnchorInfo(0, 0, null, ""))
                .add(commentThread);

        Map<String, Object> data = file.asData();

        List<BatchEmailActivityFile.FileLineData> lines = getLines(data);
        assertThat(lines, hasSize(1));
        BatchEmailActivityFile.FileLineData line = Iterables.getOnlyElement(lines);
        assertThat(line.getType(), nullValue());
        assertThat(line.getLine(), is(DiffCommentAnchor.NO_LINE));
    }

    @Test
    public void testLinesInOrderOfSourceThenDestinationLineNumber() throws Exception {
        file.getCommentThreadCollection(new DiffAnchorInfo(0, 5, DiffSegmentType.ADDED, "a"))
                .add(commentThread(0));
        file.getCommentThreadCollection(new DiffAnchorInfo(5, 5, DiffSegmentType.CONTEXT, "b"))
                .add(commentThread(0));
        file.getCommentThreadCollection(new DiffAnchorInfo(3, 0, DiffSegmentType.REMOVED, "c"))
                .add(commentThread(0));

        List<BatchEmailActivityFile.FileLineData> lines = getLines(file.asData());
        assertThat(lines, hasSize(3));
        assertEquals("a", lines.get(0).getText());
        assertEquals("c", lines.get(1).getText());
        assertEquals("b", lines.get(2).getText());
    }

    @Test
    public void testDateIsOldestNonContextCommentDate() {
        CommentThread comment1 = contextCommentThread(1);
        CommentThread comment2 = commentThread(2);
        comment1.addReply(comment2);

        CommentThread comment3 = commentThread(3);
        CommentThread comment4 = commentThread(4);
        file.getCommentThreadCollection(new DiffAnchorInfo(0, 1, DiffSegmentType.ADDED, "a"))
                .add(comment4);
        file.getCommentThreadCollection(new DiffAnchorInfo(0, 2, DiffSegmentType.ADDED, "b"))
                .add(comment1);
        file.getCommentThreadCollection(new DiffAnchorInfo(0, 3, DiffSegmentType.ADDED, "c"))
                .add(comment3);

        assertEquals(comment2.getDate(), file.getDate());
    }

    private static CommentThread commentThread(long date) {
        return commentThread(date, false);
    }

    private static CommentThread contextCommentThread(long date) {
        return commentThread(date, true);
    }

    private static CommentThread commentThread(long date, boolean context) {
        Comment comment = mock(Comment.class);
        when(comment.getCreatedDate()).thenReturn(new Date(date));
        return new CommentThread(comment, context);
    }

    @SuppressWarnings("unchecked")
    private static List<BatchEmailActivityFile.FileLineData> getLines(Map<String, Object> data) {
        return (List) data.get("lines");
    }
}
