package git

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/hashicorp/go-version"
)

func Version() (*version.Version, error) {
	var buf bytes.Buffer
	cmd := exec.Command("git", "version")
	cmd.Stdout = &buf
	cmd.Stderr = os.Stderr
	err := cmd.Run()
	if err != nil {
		return nil, err
	}
	fields := strings.Fields(buf.String())
	if len(fields) < 3 {
		return nil, fmt.Errorf("invalid git version: %s", buf.String())
	}

	// version string is like: "git version 2.29.3" or "git version 2.29.3.windows.1"
	versionString := fields[2]
	if pos := strings.Index(versionString, "windows"); pos >= 1 {
		versionString = versionString[:pos-1]
	}
	return version.NewVersion(versionString)
}

const WorkflowDir = `/.tangled/workflows`

func SparseSyncGitRepo(ctx context.Context, cloneUri, path, rev string) error {
	exist, err := isDir(path)
	if err != nil {
		return err
	}
	if rev == "" {
		rev = "HEAD"
	}
	if !exist {
		if err := exec.Command("git", "clone", "--no-checkout", "--depth=1", "--filter=tree:0", "--revision="+rev, cloneUri, path).Run(); err != nil {
			return fmt.Errorf("git clone: %w", err)
		}
		if err := exec.Command("git", "-C", path, "sparse-checkout", "set", "--no-cone", WorkflowDir).Run(); err != nil {
			return fmt.Errorf("git sparse-checkout set: %w", err)
		}
	} else {
		if err := exec.Command("git", "-C", path, "fetch", "--depth=1", "--filter=tree:0", "origin", rev).Run(); err != nil {
			return fmt.Errorf("git pull: %w", err)
		}
	}
	if err := exec.Command("git", "-C", path, "checkout", rev).Run(); err != nil {
		return fmt.Errorf("git checkout: %w", err)
	}
	return nil
}

func isDir(path string) (bool, error) {
	info, err := os.Stat(path)
	if err == nil && info.IsDir() {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}
