package execx

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"

	"github.com/suyuan32/goctls/util/pathx"
	"github.com/suyuan32/goctls/vars"
)

// RunFunc defines a function type of Run function
type RunFunc func(string, string, ...*bytes.Buffer) (string, error)

// Run provides the execution of shell scripts in golang,
// which can support macOS, Windows, and Linux operating systems.
// Other operating systems are currently not supported
func Run(arg, dir string, in ...*bytes.Buffer) (string, error) {
	goos := runtime.GOOS
	var cmd *exec.Cmd
	switch goos {
	case vars.OsMac, vars.OsLinux:
		shellEnv := os.Getenv("SHELL")
		if shellEnv == "" {
			cmd = exec.Command("sh", "-c", arg)
		} else {
			cmd = exec.Command(shellEnv, "-c", arg)
		}
	case vars.OsWindows:
		cmd = exec.Command("cmd.exe", "/c", arg)
	default:
		return "", fmt.Errorf("unexpected os: %v", goos)
	}
	if len(dir) > 0 {
		cmd.Dir = dir
	}

	cmd.Env = append(os.Environ(), "GOWORK=off")

	stdout := new(bytes.Buffer)
	stderr := new(bytes.Buffer)
	if len(in) > 0 {
		cmd.Stdin = in[0]
	}
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	err := cmd.Run()
	if err != nil {
		if stderr.Len() > 0 {
			return "", errors.New(strings.TrimSuffix(stderr.String(), pathx.NL))
		}
		return "", err
	}

	return strings.TrimSuffix(stdout.String(), pathx.NL), nil
}
