package service

import (
	"context"
	"errors"
	"io"
	"os"

	"github.com/pingcap/agent-git-service/internal/service/internal/repositorymutation"
)

// PushRepositoryMirror runs one trusted mirror transfer without exposing the
// private mutation session or its Context to the server package.
func (s *Service) PushRepositoryMirror(ctx context.Context, repositoryID uint, fullName, sourceGitDir string, refSpecs []string, output io.Writer) error {
	if s == nil || s.repositoryMutations == nil || s.Git == nil || output == nil {
		return ErrRepositoryMigrationConflict
	}
	session, err := s.repositoryMutations.AcquireSession(ctx, repositoryID, fullName)
	if err != nil {
		if errors.Is(err, repositorymutation.ErrRepositoryMutationSealed) {
			return ErrRepositoryMigrationSealed
		}
		return err
	}
	defer func() { _ = session.Release() }()
	targetGitDir, err := s.Git.GetRepoPath(ctx, fullName)
	if err != nil {
		return err
	}
	arguments := []string{"--git-dir", sourceGitDir, "push", "--no-verify", "--", targetGitDir}
	arguments = append(arguments, refSpecs...)
	process, stdout, err := session.StartCommand(ctx, "git", arguments, "", repositoryMirrorPushEnvironment(), nil, output)
	if err != nil {
		return err
	}
	if _, err := io.Copy(output, stdout); err != nil {
		_ = process.Cancel()
		_ = process.Wait()
		return err
	}
	return process.Wait()
}

func repositoryMirrorPushEnvironment() []string {
	path := os.Getenv("PATH")
	if path == "" {
		path = "/usr/bin:/bin"
	}
	environment := []string{
		"PATH=" + path,
		"HOME=/nonexistent",
		"XDG_CONFIG_HOME=/nonexistent",
		"GIT_CONFIG_GLOBAL=/dev/null",
		"GIT_CONFIG_SYSTEM=/dev/null",
		"GIT_CONFIG_NOSYSTEM=1",
		"GIT_ATTR_NOSYSTEM=1",
		"GIT_TERMINAL_PROMPT=0",
		"LC_ALL=C",
	}
	if temporary := os.Getenv("TMPDIR"); temporary != "" {
		environment = append(environment, "TMPDIR="+temporary)
	}
	return environment
}
