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

import com.atlassian.stash.internal.scm.git.UriEncodingUtils;
import com.atlassian.bitbucket.scm.ScmUrlFormatter;
import com.atlassian.bitbucket.scm.ScmUrlRequest;
import com.atlassian.bitbucket.scm.http.RepositoryUrlFragment;

import javax.annotation.Nonnull;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * @since 3.4
 */
public class GitHttpUrlFormatter implements ScmUrlFormatter {

    @Nonnull
    @Override
    public URI format(@Nonnull ScmUrlRequest request) throws URISyntaxException {
        URI uri = request.getBaseUrl();

        //noinspection ConstantConditions
        String username = request.hasUser() ? request.getUser().getName() : null;
        String path = RepositoryUrlFragment.fromRepository(request.getRepository()).toPath(uri.getPath());

        return new URI(uri.getScheme(),
                isShellSafe(username) ? username : null, // Omit the username if it appears to be CLI-unsafe
                uri.getHost(), uri.getPort(),
                path + ".git", uri.getQuery(), uri.getFragment());
    }

    /**
     * Determines if the username contains only characters that are unlikely to be interpreted by a shell
     * or Windows command prompt if used verbatim. This is not authoritative in the negative - false negatives
     * will occur for usernames with characters other than [a-zA-Z0-9~.-_].
     *
     * @return true if the username appears to contain only CLI-sensitive characters, false otherwise
     */
    private boolean isShellSafe(String username) {
        if (username == null) {
            return false;
        }

        try {
            String encodedForUri = UriEncodingUtils.encodeUserInfo(username, "UTF-8");
            String encodedForShell = UriEncodingUtils.encodeComponentForShell(username, "UTF-8");

            return encodedForUri.equals(encodedForShell);
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }
}
