package command

import (
	"bytes"
	"context"
	"errors"
	"os/exec"
	"syscall"
	"time"

	"golang.org/x/sys/windows"

	"tea.chunkbyte.com/kato/go-worm/lib/config"
	"tea.chunkbyte.com/kato/go-worm/lib/models"
)

var (
	ErrEmptyCommand = errors.New("command must not be empty")
	ErrBadTimeout   = errors.New("timeout_sec must be zero or positive")
	ErrTimeout      = errors.New("command timed out")
)

func ResolveTimeout(seconds int) (time.Duration, error) {
	if seconds < 0 {
		return 0, ErrBadTimeout
	}
	if seconds == 0 {
		seconds = config.DefaultExecTO
	}
	if seconds > config.MaxExecTO {
		seconds = config.MaxExecTO
	}
	return time.Duration(seconds) * time.Second, nil
}

func Run(ctx context.Context, cmdline string) (models.ExecResponse, error) {
	cmd := exec.CommandContext(ctx, "cmd.exe", "/C", cmdline)
	cmd.SysProcAttr = &syscall.SysProcAttr{
		HideWindow:    true,
		CreationFlags: windows.CREATE_NO_WINDOW,
	}
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	if ctx.Err() == context.DeadlineExceeded {
		return models.ExecResponse{}, ErrTimeout
	}
	exitCode := 0
	if err != nil {
		var exitErr *exec.ExitError
		if !errors.As(err, &exitErr) {
			return models.ExecResponse{}, err
		}
		exitCode = exitErr.ExitCode()
	}
	return models.ExecResponse{
		ExitCode: exitCode,
		Stdout:   stdout.String(),
		Stderr:   stderr.String(),
	}, nil
}
