package util

import (
	"os"
	"os/exec"
	"strconv"
	"strings"
)

// GetSubProcessPid 只用于一个子进程
func GetSubProcessPid(pid int) (int, error) {
	pgrepCmd := exec.Command("pgrep", "-P", strconv.Itoa(pid))
	output, err := pgrepCmd.CombinedOutput()
	if err != nil {
		return 0, err
	}
	replace := strings.Replace(string(output), "\n", "", 1)
	subProcessPid, err := strconv.Atoi(replace)
	if err != nil {
		return 0, err
	}
	return subProcessPid, nil
}

func ExecuteWithPath(path string, name string, arg ...string) (*exec.Cmd, error) {
	// 创建一个Cmd对象,表示要执行的命令
	cmd := exec.Command(name, arg...)
	// 指定目录
	cmd.Dir = path
	err := cmd.Start()
	if err != nil {
		return nil, err
	} else {
		// 执行命令并等待它完成d
		return cmd, nil
	}
}

func ExecuteWithDirAsync(dir string, name string, arg ...string) (*exec.Cmd, error) {
	// 创建一个Cmd对象,表示要执行的命令
	cmd := exec.Command(name, arg...)
	// 指定目录
	cmd.Dir = dir
	err := cmd.Start()
	if err != nil {
		return nil, err
	}
	return cmd, nil
}

func ExecuteWithEnvAndDirAsync(envs []string, dir string, name string, arg ...string) (*exec.Cmd, error) {
	cmd := exec.Command(name, arg...)
	cmd.Dir = dir
	for _, env := range envs {
		cmd.Env = append(cmd.Env, env)
	}
	if err := cmd.Start(); err != nil {
		return nil, err
	}
	return cmd, nil
}

// KillProcessByPid 必须使用该golang原生方法,通过直接执行kill命令行不通。
func KillProcessByPid(pid int) error {
	process, err := os.FindProcess(pid)
	if err != nil {
		return err
	}
	err = process.Kill()
	if err != nil {
		return err
	}
	return nil
}

func Execute(name string, arg ...string) (*exec.Cmd, string, error) {
	cmd := exec.Command(name, arg...)
	combinedOutput, err := cmd.CombinedOutput()
	if err != nil {
		return nil, "", err
	}
	return cmd, string(combinedOutput), nil
}

func ExecuteSync(name string, arg ...string) (*exec.Cmd, string, error) {
	cmd := exec.Command(name, arg...)
	combinedOutput, err := cmd.CombinedOutput()
	if err != nil {
		return nil, "", err
	}
	return cmd, string(combinedOutput), nil
}

func ExecuteWithDirSync(dir string, name string, arg ...string) (*exec.Cmd, string, error) {
	cmd := exec.Command(name, arg...)
	cmd.Dir = dir
	combinedOutput, err := cmd.CombinedOutput()
	if err != nil {
		return nil, "", err
	}
	return cmd, string(combinedOutput), nil
}

func ExecuteWithEnvSync(envs []string, name string, arg ...string) (*exec.Cmd, string, error) {
	cmd := exec.Command(name, arg...)
	for _, env := range envs {
		cmd.Env = append(cmd.Env, env)
	}
	combinedOutput, err := cmd.CombinedOutput()
	if err != nil {
		return nil, "", err
	}
	return cmd, string(combinedOutput), nil
}

func ExecuteWithEnvAndDir(envs []string, dir string, name string, arg ...string) (*exec.Cmd, string, error) {
	cmd := exec.Command(name, arg...)
	cmd.Dir = dir
	for _, env := range envs {
		cmd.Env = append(cmd.Env, env)
	}
	combinedOutput, err := cmd.CombinedOutput()
	if err != nil {
		return nil, string(combinedOutput), err
	}
	return cmd, string(combinedOutput), nil
}