package shared

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

type CommandResponse struct {
	Stdout   string `json:"stdout"`
	Stderr   string `json:"stderr"`
	ExitCode int    `json:"exitCode"`
}

type ErrorResponse struct {
	Description string `json:"description"`
}

var BadRequestDescription string = "Request uses invalid JSON syntax or does not follow request schema."

func RunShellCommand(cmd *exec.Cmd) CommandResponse {
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()

	return parseCmdResult(cmd, stdout, stderr, err)

}

func RunShellCommandNonBlocking(cmd *exec.Cmd) CommandResponse {
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	cmd.Start()

	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel()

	done := make(chan error, 1)

	go func() {
		done <- cmd.Wait()
	}()

	select {
	case <-ctx.Done():
		return CommandResponse{}
	case err := <-done:
		return parseCmdResult(cmd, stdout, stderr, err)
	}
}

func parseCmdResult(cmd *exec.Cmd, stdout, stderr bytes.Buffer, err error) CommandResponse {
	commandOutput := CommandResponse{
		Stdout:   stdout.String(),
		Stderr:   stderr.String(),
		ExitCode: cmd.ProcessState.ExitCode(),
	}
	if err != nil {
		var exitErr *exec.ExitError
		if errors.As(err, &exitErr) {
			commandOutput.ExitCode = exitErr.ExitCode()
		} else {
			commandOutput.Stderr = err.Error()
		}
	}

	return commandOutput
}
