//go:build !windows

package utils

import (
	"agent/commons/debug"
	"agent/modules/console/defines/merrs"
	"fmt"
	"os"
	"syscall"

	"github.com/shirou/gopsutil/v3/process"
)

// KillProcessTree рекурсивно завершает процесс и все его дочерние процессы
func KillProcessTree(pid int64) error {
	children, _ := FindChildProcesses(pid)
	for _, child := range children {
		_ = KillProcessTree(child)
	}
	return KillSingleProcess(pid)
}

// FindChildProcesses возвращает список дочерних процессов для заданного PID
func FindChildProcesses(parentPID int64) ([]int64, error) {
	var children []int64

	procs, err := process.Processes()
	if err != nil {
		return nil, merrs.NewFailedListProcessError(err.Error())
	}

	for _, proc := range procs {
		ppid, err := proc.Ppid()
		if err != nil {
			continue
		}

		if int64(ppid) == parentPID {
			children = append(children, int64(proc.Pid))
		}
	}

	return children, nil
}

// KillSingleProcess завершает процесс по PID
func KillSingleProcess(pid int64) (err error) {
	debug.Logf("Killing process, PID: %d\n", pid)

	defer func() {
		if err != nil {
			err = merrs.Join(err, merrs.NewFailedKillProcessError(fmt.Sprintf(`pid "%d"`, pid)))
		}
	}()

	process, err := os.FindProcess(int(pid))
	if err != nil {
		return merrs.Join(err, merrs.NewFailedFindProcessError())
	}

	err = process.Signal(syscall.SIGTERM)
	if err != nil {
		return merrs.Join(err, merrs.NewFailedSignalProcessError())
	}

	return nil
}

// KillChildProcess завершает дочерние процессы по PID
func KillChildProcess(pid int64) error {
	children, _ := FindChildProcesses(pid)
	for _, child := range children {
		_ = KillProcessTree(child)
	}
	return nil
}
