package com.atlassian.stash.internal.scm.http;

import com.atlassian.stash.internal.scm.protocol.http.DefaultHttpUrlFormatter;
import com.atlassian.bitbucket.project.Project;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.scm.ScmUrlRequest;
import com.atlassian.bitbucket.user.ApplicationUser;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.net.URI;

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

@RunWith(MockitoJUnitRunner.class)
public class DefaultHttpUrlFormatterTest {

    private static final String KEY = "KEY";
    private static final String SLUG = "slug";

    @Mock
    private Project project;
    @Mock
    private Repository repository;

    @Before
    public void setup() {
        when(project.getKey()).thenReturn(KEY);

        when(repository.getProject()).thenReturn(project);
        when(repository.getSlug()).thenReturn(SLUG);
        when(repository.getScmId()).thenReturn("git");
    }

    @Test
    public void testFormat() throws Exception {
        assertEquals("http://localhost/key/slug", format("http://localhost"));
        assertEquals("http://localhost/key/slug", format("http://localhost/"));
        assertEquals("http://localhost/stash/key/slug", format("http://localhost/stash"));
        assertEquals("http://localhost/stash/key/slug", format("http://localhost/stash/"));

        //Verify port handling works as expected
        assertEquals("http://localhost:7990/key/slug", format("http://localhost:7990"));
        assertEquals("http://localhost:7990/key/slug", format("http://localhost:7990/"));
        assertEquals("http://localhost:7990/bitbucket/scm/key/slug", format("http://localhost:7990/bitbucket/scm"));
        assertEquals("http://localhost:7990/bitbucket/scm/key/slug", format("http://localhost:7990/bitbucket/scm/"));

        //Verify the context user is formatted into the URL if provided
        assertEquals("http://bturner@localhost/key/slug", format("http://localhost", user("bturner")));
        assertEquals("http://bturner@localhost:7990/key/slug", format("http://localhost:7990/", user("bturner")));
        assertEquals("http://bturner@localhost/key/slug", format("http://scm@localhost", user("bturner")));
        assertEquals("http://bturner@localhost:7990/key/slug", format("http://scm@localhost:7990/", user("bturner")));
    }

    @Test
    public void testFormatWithCLIUnfriendlyUsername() throws Exception {
        assertEquals("http://localhost/scm/key/slug", format("http://localhost/scm", user("<script>alert('hello, world')</script>")));
        assertEquals("http://localhost/scm/key/slug", format("http://localhost/scm", user("user&")));
    }

    @Test
    public void testFormatWithURIEncodedUsername() throws Exception {
        assertEquals("http://hinch%2Fjason@localhost:7990/bitbucket/scm/key/slug", format("http://localhost:7990/bitbucket/scm", user("hinch/jason")));
        assertEquals("http://user%40example.com@localhost/scm/key/slug", format("http://localhost/scm", user("user@example.com")));
    }

    private static ApplicationUser user(String name) {
        ApplicationUser user = mock(ApplicationUser.class);
        when(user.getName()).thenReturn(name);

        return user;
    }

    private String format(String baseUrl) throws Exception {
        return format(baseUrl, null);
    }

    private String format(String baseUrl, ApplicationUser user)  throws Exception {
        return new DefaultHttpUrlFormatter()
                .format(new ScmUrlRequest.Builder(repository, new URI(baseUrl)).user(user).build())
                .toASCIIString();
    }
}