package utils

import (
	"bytes"
	"fmt"
	"os/exec"
	"syscall"
	"time"
)

func RunCommandWithTimeout(timeout int, workDir string, command string, env []string, args ...string) (exitCode int, stdout, stderr string, isKilled bool) {
	var stdoutBuf, stderrBuf bytes.Buffer
	cmd := exec.Command(command, args...)
	if env != nil {
		cmd.Env = env
	}
	//cmd.Env = append(cmd.Env, "all_proxy=socks5://127.0.0.1:7890", "http_proxy=http://127.0.0.1:7890", "https_proxy=http://127.0.0.1:7890")
	cmd.Stdout = &stdoutBuf
	cmd.Stderr = &stderrBuf
	cmd.Dir = workDir
	err := cmd.Start()
	if err != nil {
		return cmd.ProcessState.ExitCode(), "", err.Error(), true
	}
	done := make(chan error)
	go func() {
		done <- cmd.Wait()
	}()
	after := time.After(time.Duration(timeout) * time.Millisecond)
	select {
	case <-after:
		if err := cmd.Process.Signal(syscall.SIGINT); err != nil {
			return cmd.ProcessState.ExitCode(), "", err.Error(), true
		}
		time.Sleep(10 * time.Millisecond)
		if err := cmd.Process.Kill(); err != nil && err.Error() != "os: process already finished" {
			return cmd.ProcessState.ExitCode(), "", err.Error(), true
		}
		isKilled = true
		return cmd.ProcessState.ExitCode(), "", fmt.Sprintf("command execution timeout. command: %s arg: %s", command, args), true
	case <-done:
		isKilled = false
	}

	return cmd.ProcessState.ExitCode(), string(bytes.TrimSpace(stdoutBuf.Bytes())), string(bytes.TrimSpace(stderrBuf.Bytes())), false
}
