//go:build !windows

package infra

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

// ProcessSpawn launches a subprocess using the given shell.
// If shell is empty, "sh" is used. If command contains newlines it is treated
// as a multi-line script: the content is written to a temp file and executed
// with `shell <tempfile>`. Otherwise it is executed with `shell -c <command>`.
// dir sets the working directory (empty = inherit). env sets the environment
// (nil = inherit parent env). The process group is created with Setpgid so
// that ProcessKill can target the whole group.
func ProcessSpawn(command string, dir string, env []string, shell string) (*ProcessHandle, error) {
	if shell == "" {
		shell = "sh"
	}

	var cmd *exec.Cmd

	if strings.Contains(command, "\n") {
		// Multi-line script: write to a temp file and execute it.
		tmp, err := os.CreateTemp("", "fn-proc-*.sh")
		if err != nil {
			return nil, fmt.Errorf("process_spawn: create temp file: %w", err)
		}
		if _, err := tmp.WriteString(command); err != nil {
			_ = os.Remove(tmp.Name())
			return nil, fmt.Errorf("process_spawn: write temp file: %w", err)
		}
		if err := tmp.Close(); err != nil {
			_ = os.Remove(tmp.Name())
			return nil, fmt.Errorf("process_spawn: close temp file: %w", err)
		}
		cmd = exec.Command(shell, tmp.Name())
	} else {
		cmd = exec.Command(shell, "-c", command)
	}

	if dir != "" {
		cmd.Dir = dir
	}
	if len(env) > 0 {
		cmd.Env = env
	}

	// New process group so we can kill all children as a group.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

	// Use buffers instead of pipes to avoid race between Wait() and ReadAll().
	var stdoutBuf, stderrBuf bytes.Buffer
	cmd.Stdout = &stdoutBuf
	cmd.Stderr = &stderrBuf

	start := time.Now()
	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("process_spawn: start: %w", err)
	}

	return &ProcessHandle{
		Cmd:       cmd,
		Pid:       cmd.Process.Pid,
		StartTime: start,
		Dir:       dir,
		stdout:    &stdoutBuf,
		stderr:    &stderrBuf,
	}, nil
}
