package utils

// Description: Structs to execute external commands.

import (
	"fmt"
	"io"
	"log"
	"os/exec"
	"strings"
)

// Executor is a struct that holds the standard output and error writers,
// as well as a logger for logging command execution.
// It can be used to run shell commands and log their output.
type Executor struct {
	Stdout, Stderr io.Writer
	Logger         *log.Logger
}

// Run executes a command in the shell and logs the command being run.
func (e *Executor) Run(full_cmd string) error {
	e.Logger.Println(full_cmd)
	split := strings.Split(full_cmd, " ")
	cmd := exec.Command(split[0], split[1:]...)
	cmd.Stdout = e.Stdout
	cmd.Stderr = e.Stderr
	status := cmd.Run()
	if status != nil {
		e.Logger.Println(status)
	}
	return status
}

// PanicOnFail uses Run to execute a command and panics if the command fails.
func (e *Executor) PanicOnFail(full_cmd string) {
	if err := e.Run(full_cmd); err != nil {
		panic(fmt.Errorf("%s failed: %w", full_cmd, err))
	}
}

// Pager is a struct to display files using a pager command (e.g., "less").
type Pager struct {
	executor *Executor
	cmd      string
}

// NewPager creates a new Pager instance and returns a pointer to it. It sets
// the command to be used for paging, defaulting to the value of the "PAGER"
// environment variable. If "PAGER" is not set, it uses the provided
// FallbackPager value.
func NewPager(exec *Executor, FallbackPager string) *Pager {
	return &Pager{exec, SetEnvIfNotSet("PAGER", FallbackPager)}
}

// Display executes the pager command with the provided files.
func (p *Pager) Display(files ...string) {
	p.executor.PanicOnFail(p.cmd + " " + strings.Join(files, " "))
}
