package git

import (
	"bytes"
	"fmt"
	"net/url"
	"os/exec"
	"strings"

	"github.com/pkg/errors"
	catUtil "github.com/rancher/rancher/pkg/catalog/utils"
)

func Clone(path, url, branch string) error {
	if err := catUtil.ValidateURL(url); err != nil {
		return err
	}
	return runcmd("git", "clone", "-b", branch, "--single-branch", url, path)
}

func Update(path, commit string) error {
	if err := runcmd("git", "-C", path, "fetch"); err != nil {
		return err
	}
	return runcmd("git", "-C", path, "checkout", commit)
}

func HeadCommit(path string) (string, error) {
	cmd := exec.Command("git", "-C", path, "rev-parse", "HEAD")
	output, err := cmd.Output()
	return strings.Trim(string(output), "\n"), err
}

func RemoteBranchHeadCommit(url, branch string) (string, error) {
	if err := catUtil.ValidateURL(url); err != nil {
		return "", err
	}
	cmd := exec.Command("git", "ls-remote", url, branch)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return "", errors.Wrap(err, string(output))
	}
	parts := strings.Split(string(output), "\t")
	if len(parts) > 0 && len(parts[0]) > 0 {
		return parts[0], nil
	}
	return "", fmt.Errorf("no commit found for url %s branch %s", branch, url)
}

func IsValid(url string) bool {
	if err := catUtil.ValidateURL(url); err != nil {
		return false
	}
	err := runcmd("git", "ls-remote", url)
	return err == nil
}

func runcmd(name string, arg ...string) error {
	cmd := exec.Command(name, arg...)
	bufErr := &bytes.Buffer{}
	cmd.Stderr = bufErr
	if err := cmd.Run(); err != nil {
		return errors.Wrap(err, bufErr.String())
	}
	return nil
}

// FormatURL generates request url if is a private catalog
func FormatURL(pathURL, username, password string) string {
	if len(username) > 0 && len(password) > 0 {
		if u, err := url.Parse(pathURL); err == nil {
			u.User = url.UserPassword(username, password)
			return u.String()
		}
	}
	return pathURL
}

func CloneWithDepth(path, url, branch string, depth int) error {
	if err := catUtil.ValidateURL(url); err != nil {
		return err
	}
	return runcmd("git", "clone", "-b", branch, "--single-branch", fmt.Sprintf("--depth=%v", depth), url, path)
}
