package com.atlassian.stash.internal.notification.mention;

import com.atlassian.bitbucket.DataGenerationUtils;
import com.atlassian.bitbucket.auth.AuthenticationContext;
import com.atlassian.bitbucket.hamcrest.RegexMatcher;
import com.atlassian.bitbucket.request.RequestContext;
import com.atlassian.bitbucket.user.TestApplicationUser;
import com.atlassian.bitbucket.user.UserService;
import com.atlassian.markup.renderer.impl.TokenReplacer;
import com.atlassian.markup.renderer.impl.TransformUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.junit.Test;

import java.io.IOException;
import java.util.Arrays;
import java.util.regex.Pattern;

import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class MentionRendererComponentTest {

    @Test
    public void testProcess() throws Exception {
        process("Bad. @a and @b need to fix this", "Bad. <span.*?>User &lt;script&gt;</span> and <span.*?>User B</span> need to fix this");
    }

    @Test
    public void testProcessNoUser() throws Exception {
        process("Bad. @a and @c need to fix this", "Bad. <span.*?>User &lt;script&gt;</span> and @c need to fix this");
    }

    @Test
    public void testProcessUserInQuotes() throws Exception {
        process("@\"a\"", "<span.*?>User &lt;script&gt;</span>");
    }

    @Test
    public void testMissingUserEscapesFullMentionIncludingQuotes() throws Exception {
        process("Bad. @\"a<b\"", "Bad. @&quot;a&lt;b&quot;");
    }

    @Test
    public void testMissingUserEscapesFullMentionButNotQuotHtmlEntity() throws Exception {
        process("@&quot;a<b&quot;", "@&quot;a&lt;b&quot;");
    }

    @Test
    public void testSameNameWithAndWithoutQuotesIsTreatedDifferently() throws Exception {
        process("@missing @\"missing\"", "@missing @&quot;missing&quot;");
    }

    @Test
    public void testCurrentUser() throws Exception {
        process("@b", "<span class=\".*?current-user.*?\">User B</span>", new TestApplicationUser("b"));
    }

    @Test
    public void testEscapedMarkdown() throws Exception {
        process("@d", "<span.*?>!\\[alt\\]\\(image\\)</span>");
    }

    @Test
    public void testQAUser() throws Exception {
        String user = DataGenerationUtils.MAX_STASH_USER_NAME.replace("\"", "\\\"");
        process(String.format("@\"%s\"", user), Pattern.quote(String.format("@&quot;%s&quot;", StringEscapeUtils.escapeHtml4(user.replace("\\", "")))));
    }

    private void process(String in, String expected) throws IOException {
        process(in, expected, null);
    }

    private void process(String in, String expected, TestApplicationUser current) throws IOException {
        RequestContext requestContext = mock(RequestContext.class);
        UserService userService = mock(UserService.class);
        when(userService.getUserByName("a")).thenReturn(new TestApplicationUser("User <script>"));
        when(userService.getUserByName("b")).thenReturn(new TestApplicationUser("User B"));
        when(userService.getUserByName("d")).thenReturn(new TestApplicationUser("![alt](image)"));
        AuthenticationContext authContext = mock(AuthenticationContext.class);
        when(authContext.getCurrentUser()).thenReturn(current);
        MentionRendererComponent stage = new MentionRendererComponent(authContext, requestContext, userService);
        TokenReplacer tokenReplacer = TransformUtils.tokenReplace(in, Arrays.asList(stage.process(in, null)));
        assertThat(tokenReplacer.resolve(tokenReplacer.getIntermediate()).toString(), RegexMatcher.matchesRegex(expected));
    }

}
