package exec

import (
	"bytes"
	"context"
	"golang.org/x/sync/errgroup"
	"os/exec"
	"time"
)

type RunOptions struct {
	Timeout time.Duration
}

type CommandRunner interface {
	Run(ctx context.Context, cmd string, args []string, opts RunOptions) (string, string, error)
}

type DefaultRunner struct{}

func (r *DefaultRunner) Run(ctx context.Context, cmd string, args []string, opts RunOptions) (string, string, error) {
	var stdout, stderr bytes.Buffer
	execCtx := ctx
	if opts.Timeout > 0 {
		var cancel context.CancelFunc
		execCtx, cancel = context.WithTimeout(ctx, opts.Timeout)
		defer cancel()
	}

	eg, cctx := errgroup.WithContext(execCtx)

	eg.Go(func() error {
		command := exec.CommandContext(cctx, cmd, args...)
		command.Stdout = &stdout
		command.Stderr = &stderr
		return command.Run()
	})
	if err := eg.Wait(); err != nil {
		return stdout.String(), stderr.String(), err
	}
	return stdout.String(), stderr.String(), nil
}
