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

import com.atlassian.bitbucket.io.LineReader;
import com.atlassian.bitbucket.io.LineReaderOutputHandler;
import com.atlassian.bitbucket.scm.CommandOutputHandler;
import com.atlassian.bitbucket.scm.git.command.GitCommandBuilderFactory;
import com.atlassian.bitbucket.scm.git.command.GitScmCommandBuilder;
import com.confluex.mock.http.MockHttpServer;
import com.google.common.collect.ImmutableList;
import org.junit.*;

import javax.annotation.Resource;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;

import static com.confluex.mock.http.matchers.HttpMatchers.get;
import static com.confluex.mock.http.matchers.HttpMatchers.header;
import static org.hamcrest.Matchers.equalTo;

public class GitAuthUtilsTest extends AbstractGitTest {

    private static final String PASSWORD = "http-auth-pwd";
    private static final String USERNAME = "http-auth-user";
    private static final String AUTH_TOKEN = USERNAME + ":" + PASSWORD;
    private static final String EXPECTED_BASIC_AUTH = "Basic " + Base64.getEncoder()
            .encodeToString(AUTH_TOKEN.getBytes(StandardCharsets.UTF_8));

    @Resource
    private GitCommandBuilderFactory builderFactory;

    @Resource
    private InternalGitScmConfig config;
    private MockHttpServer httpServer;

    @Before
    public void setUp() throws Exception {
        httpServer = new MockHttpServer();
        httpServer.respondTo(get()).withStatus(401).withHeader("WWW-Authenticate", "Basic realm=\"Atlassian Bitbucket\"");
        httpServer.respondTo(get().and(header("Authorization", EXPECTED_BASIC_AUTH)))
                .withStatus(200)
                .withHeader("Content-Type", "application/x-git-upload-pack-advertisement")
                .withBody("76d28b849be7fb3301e4bd14fb28328947b4f5a1\tHEAD\n" +
                        "76d28b849be7fb3301e4bd14fb28328947b4f5a1\trefs/heads/master\n");
    }

    @After
    public void tearDown() throws Exception {
        if (httpServer != null) {
            httpServer.stop();
            httpServer = null;
        }
    }

    @Test
    public void testConfigurePasswordHttp() {
        String cloneUrl = String.format("http://%s@127.0.0.1:%d/scm/proj/repo.git", USERNAME, httpServer.getPort());
        List<String> refIds = lsRemoteWithPassword(cloneUrl, PASSWORD);

        assertThat("refs retrieved", refIds, equalTo(ImmutableList.of("HEAD", "refs/heads/master")));
    }

    private List<String> lsRemoteWithPassword(String url, String password) {
        GitScmCommandBuilder builder = builderFactory.builder().command("ls-remote").argument(url);
        GitAuthUtils.configurePassword(builder, config, password);
        return builder.build(new LsRemoteOutputHandler()).call();
    }

    private static class LsRemoteOutputHandler extends LineReaderOutputHandler implements CommandOutputHandler<List<String>> {

        private final ImmutableList.Builder<String> refs;

        public LsRemoteOutputHandler() {
            super(StandardCharsets.UTF_8);

            refs = ImmutableList.builder();
        }

        @Override
        public List<String> getOutput() {
            return refs.build();
        }

        @Override
        protected void processReader(LineReader reader) throws IOException {
            String line;
            while ((line = reader.readLine()) != null) {
                // 76d28b849be7fb3301e4bd14fb28328947b4f5a1\tHEAD - only get the refId
                int refIdStart = line.indexOf('\t') + 1;
                if (refIdStart > 0 && refIdStart < line.length()) {
                    refs.add(line.substring(refIdStart));
                }
            }
        }
    }
}