package com.atlassian.bitbucket.internal.mirroring.mirror.nav;

import com.atlassian.bitbucket.internal.mirroring.mirror.InternalUpstreamServer;
import com.atlassian.bitbucket.internal.mirroring.mirror.MirroringConfig;
import com.atlassian.bitbucket.mirroring.mirror.UpstreamAccount;
import com.atlassian.bitbucket.mirroring.mirror.UpstreamServerType;
import com.atlassian.bitbucket.nav.NavBuilder;
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.URLEncoder;

import static com.atlassian.bitbucket.internal.mirroring.mirror.nav.DefaultMirroringNavBuilderTest.assertUrlWithParams;
import static java.util.Optional.of;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class DefaultCloudUpstreamNavBuilderTest {

    private static final String BASEURL = "http://bitbucket.company.com/bitbucket";
    private static final String BITBUCKET_URL = "https://bitbucket.org";
    private static final String BITBUCKET_API_URL = "https://api.bitbucket.org";
    private static final String TEAM_ID = "team-id";
    private static final String TEAM_NAME = "team-name";
    private static final String UPSTREAM_ID = "upstream-id";
    private static final String ADDON_KEY = "bitbucket.mirror.server-id";

    @Mock
    private MirroringConfig config;
    @Mock
    private NavBuilder navBuilder;
    @Mock
    private InternalUpstreamServer upstream;
    @Mock
    private UpstreamAccount account;
    private DefaultCloudUpstreamNavBuilder builder;
    private DefaultMirroringNavBuilder mirroringNavBuilder;

    @Before
    public void setUpNavBuilder() {
        when(navBuilder.buildAbsolute()).thenReturn(BASEURL);

        when(upstream.getBaseUrl()).thenReturn(BITBUCKET_URL);
        when(upstream.getApiBaseUrl()).thenReturn(BITBUCKET_API_URL);
        when(upstream.getType()).thenReturn(UpstreamServerType.BITBUCKET_CLOUD);
        when(upstream.getId()).thenReturn(UPSTREAM_ID);
        when(upstream.getAccount()).thenReturn(of(account));

        when(account.getId()).thenReturn(TEAM_ID);
        when(account.getName()).thenReturn(TEAM_NAME);

        when(config.getAddonKey()).thenReturn(ADDON_KEY);

        mirroringNavBuilder = new DefaultMirroringNavBuilder(config, navBuilder);
        builder = new DefaultCloudUpstreamNavBuilder(config, mirroringNavBuilder, upstream);
    }

    @Test
    public void testAddonStatus() throws Exception {
        assertEquals(BITBUCKET_API_URL + "/internal/account/" + TEAM_ID + "/addons/" + ADDON_KEY + "/status", builder.addonStatus(ADDON_KEY).getAbsolute());
    }

    @Test
    public void testAdminRestUrl() {
        assertEquals(BITBUCKET_URL + "/account/user/" + TEAM_NAME + "/addon/configure/" + ADDON_KEY + "/mirror-config",
                builder.admin().getAbsolute());
    }

    @Test
    public void testAuthorizeAddonRestUrl() throws Exception {
        assertUrlWithParams(
                BITBUCKET_URL + "/site/addons/authorize",
                new String[] {
                        "descriptor_uri=" + URLEncoder.encode(
                                mirroringNavBuilder.rest()
                                    .upstreamServer(upstream.getId())
                                    .addon()
                                    .descriptor()
                                    .getAbsolute(), "UTF-8"),
                        "redirect_uri=" + URLEncoder.encode(
                                mirroringNavBuilder
                                    .placeholder()
                                    .getAbsolute(), "UTF-8")
                },
                builder.authorizeAddon().getAbsolute());
    }

    @Test
    public void testOauthAccessToken() throws Exception {
        assertEquals(BITBUCKET_URL + "/site/oauth2/access_token",
                builder.oauth2().accessToken().getAbsolute());
    }

    @Test
    public void testRelativeToBase() throws Exception {
        assertEquals(BITBUCKET_URL + "/foo/bar/baz",
                builder.relativeToBase("/foo/bar/baz").getAbsolute());
        // we don't say we will accept this but we try to be tolerant in what we accept
        assertEquals(BITBUCKET_URL + "/foo/bar/baz",
                builder.relativeToBase("foo/bar/baz").getAbsolute());
    }

    @Test
    public void testUpstreamRepositories() {
        assertUrlWithParams(BITBUCKET_API_URL + "/2.0/repositories/" + TEAM_ID,
                new String[] {
                    "pagelen=100",
                    "fields=" +
                            "values.parent.owner%2C" +
                            "values.parent.updated_on%2C" +
                            "values.parent.parent.owner%2C" +
                            "values.parent.parent.updated_on%2C" +
                            "values.parent.parent.parent.owner%2C" +
                            "values.parent.parent.parent.updated_on%2C" +
                            "values.parent.parent.parent.parent.owner%2C" +
                            "values.parent.parent.parent.parent.updated_on%2C" +
                            "values.parent.parent.parent.parent.parent.owner%2C" +
                            "values.parent.parent.parent.parent.parent.updated_on"
                },
                builder.repositories(100).getAbsolute());
    }

    @Test
    public void testUpstreamRepositoryById() {
        assertUrlWithParams(BITBUCKET_API_URL + "/2.0/repositories/%7B%7D/%7B1%7D",
                new String[] {
                        "fields=" +
                                "parent.owner%2C" +
                                "parent.updated_on%2C" +
                                "parent.parent.owner%2C" +
                                "parent.parent.updated_on%2C" +
                                "parent.parent.parent.owner%2C" +
                                "parent.parent.parent.updated_on%2C" +
                                "parent.parent.parent.parent.owner%2C" +
                                "parent.parent.parent.parent.updated_on%2C" +
                                "parent.parent.parent.parent.parent.owner%2C" +
                                "parent.parent.parent.parent.parent.updated_on"
                },
                builder.repositoryById("{1}").getAbsolute());
    }

    @Test
    public void testUpstreamRepositoryBySlug() {
        assertUrlWithParams(BITBUCKET_API_URL + "/2.0/repositories/" + TEAM_ID + "/myrepo",
                new String[] {
                        "fields=" +
                                "parent.owner%2C" +
                                "parent.updated_on%2C" +
                                "parent.parent.owner%2C" +
                                "parent.parent.updated_on%2C" +
                                "parent.parent.parent.owner%2C" +
                                "parent.parent.parent.updated_on%2C" +
                                "parent.parent.parent.parent.owner%2C" +
                                "parent.parent.parent.parent.updated_on%2C" +
                                "parent.parent.parent.parent.parent.owner%2C" +
                                "parent.parent.parent.parent.parent.updated_on"
                },
                builder.repositoryBySlug("myrepo").getAbsolute());
    }

    @Test
    public void testUpstreamPermission() {
        assertEquals(BITBUCKET_API_URL + "/internal/repositories/" + TEAM_NAME + "/%7B1%7D/permission",
                builder.repositoryPermissionBySlug("{1}").getAbsolute());
    }

    @Test
    public void testUpstreamAccount() throws Exception {
        assertEquals(BITBUCKET_API_URL + "/2.0/teams/" + TEAM_ID,
                builder.account().getAbsolute());

    }
}