package gitauth

import (
	"net/url"
	"regexp"
	"strings"

	"golang.org/x/xerrors"
)

// https://github.com/microsoft/vscode/blob/328646ebc2f5016a1c67e0b23a0734bd598ec5a8/extensions/git/src/askpass-main.ts#L46
var hostReplace = regexp.MustCompile(`^["']+|["':]+$`)

// CheckCommand returns true if the command arguments and environment
// match those when the GIT_ASKPASS command is invoked by git.
func CheckCommand(args, env []string) bool {
	if len(args) != 1 || (!strings.HasPrefix(args[0], "Username ") && !strings.HasPrefix(args[0], "Password ")) {
		return false
	}
	for _, e := range env {
		if strings.HasPrefix(e, "GIT_PREFIX=") {
			return true
		}
	}
	return false
}

// ParseAskpass returns the user and host from a git askpass prompt. For
// example: "user1" and "https://github.com". Note that for HTTP
// protocols, the URL will never contain a path.
//
// For details on how the prompt is formatted, see `credential_ask_one`:
// https://github.com/git/git/blob/bbe21b64a08f89475d8a3818e20c111378daa621/credential.c#L173-L191
func ParseAskpass(prompt string) (user string, host string, err error) {
	parts := strings.Fields(prompt)
	if len(parts) < 3 {
		return "", "", xerrors.Errorf("askpass prompt must contain 3 words; got %d: %q", len(parts), prompt)
	}

	switch parts[0] {
	case "Username", "Password":
	default:
		return "", "", xerrors.Errorf("unknown prompt type: %q", prompt)
	}

	host = parts[2]
	host = hostReplace.ReplaceAllString(host, "")

	// Validate the input URL to ensure it's in an expected format.
	u, err := url.Parse(host)
	if err != nil {
		return "", "", xerrors.Errorf("parse host failed: %w", err)
	}

	switch u.Scheme {
	case "http", "https":
	default:
		return "", "", xerrors.Errorf("unsupported scheme: %q", u.Scheme)
	}

	if u.Host == "" {
		return "", "", xerrors.Errorf("host is empty")
	}

	user = u.User.Username()
	u.User = nil
	host = u.String()

	return user, host, nil
}
