package git

import (
	"bufio"
	"bytes"
	"context"
	"strings"
)

// FetchRemoteBranch fetches a single remote branch (origin/<branch>).
// Lighter than Fetch --all when we only need one branch.
func (r *DefaultRunner) FetchRemoteBranch(ctx context.Context, dir, branch string, cred *Credential) error {
	ctx, cancel := withCtx(ctx, r.cfg.FetchTimeout)
	defer cancel()
	env, cleanup, err := credentialEnv(r.cfg.TmpDir, cred)
	if err != nil {
		return err
	}
	defer cleanup()
	_, _, err = r.exec(ctx, dir, env, "fetch", "origin", branch)
	return err
}

// Checkout switches the working tree to the given branch.
func (r *DefaultRunner) Checkout(ctx context.Context, dir, branch string) error {
	ctx, cancel := withCtx(ctx, r.cfg.OpsTimeout)
	defer cancel()
	_, _, err := r.exec(ctx, dir, nil, "checkout", branch)
	return err
}

// ListRemoteBranches queries the remote for all branch names via git ls-remote.
// Returns branch names with refs/heads/ prefix stripped.
func (r *DefaultRunner) ListRemoteBranches(ctx context.Context, dir string, cred *Credential) ([]string, error) {
	ctx, cancel := withCtx(ctx, r.cfg.FetchTimeout)
	defer cancel()
	env, cleanup, err := credentialEnv(r.cfg.TmpDir, cred)
	if err != nil {
		return nil, err
	}
	defer cleanup()
	out, _, err := r.exec(ctx, dir, env, "ls-remote", "--heads")
	if err != nil {
		return nil, err
	}
	return parseRemoteBranches(out), nil
}

// parseRemoteBranches parses git ls-remote --heads output.
// Each line: "<sha>\trefs/heads/<branch>"
func parseRemoteBranches(buf []byte) []string {
	var branches []string
	sc := bufio.NewScanner(bytes.NewReader(buf))
	for sc.Scan() {
		line := strings.TrimSpace(sc.Text())
		if idx := strings.Index(line, "\trefs/heads/"); idx >= 0 {
			name := line[idx+len("\trefs/heads/"):]
			if name != "" {
				branches = append(branches, name)
			}
		}
	}
	return branches
}
