package verbose

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

// RunCommand executes cmd.CombinedOutput() and logs the command name,
// exit status, and duration when verbose mode is enabled.
// Output is not logged to avoid leaking secrets (tokens, kubeconfigs, etc.).
func RunCommand(cmd *exec.Cmd) ([]byte, error) {
	return runCommand(cmd, true)
}

// RunCommandStdout returns clean stdout on success and includes stderr on failure.
func RunCommandStdout(cmd *exec.Cmd) ([]byte, error) {
	return runCommand(cmd, false)
}

func runCommand(cmd *exec.Cmd, combineOutput bool) ([]byte, error) {
	if !Enabled() {
		return commandOutput(cmd, combineOutput)
	}

	Logf("EXEC %s", commandString(cmd))

	start := time.Now()
	output, err := commandOutput(cmd, combineOutput)
	elapsed := time.Since(start)

	if err != nil {
		Logf("EXEC <<< FAILED (%s): %v", elapsed, err)
	} else {
		Logf("EXEC <<< OK (%s, %d bytes output)", elapsed, len(output))
	}

	return output, err
}

func commandOutput(cmd *exec.Cmd, combineOutput bool) ([]byte, error) {
	if combineOutput {
		return cmd.CombinedOutput()
	}
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		stdout.Write(stderr.Bytes())
	}
	return stdout.Bytes(), err
}

// StartCommand starts a long-running command and logs its start when verbose
// mode is enabled. Callers remain responsible for waiting and logging readiness
// or termination because long-running tools usually stream until closed.
func StartCommand(cmd *exec.Cmd) error {
	if !Enabled() {
		return cmd.Start()
	}

	Logf("EXEC START %s", commandString(cmd))
	if err := cmd.Start(); err != nil {
		Logf("EXEC START <<< FAILED: %v", err)
		return err
	}
	if cmd.Process != nil {
		Logf("EXEC START <<< OK pid=%d", cmd.Process.Pid)
	} else {
		Logf("EXEC START <<< OK")
	}
	return nil
}

func commandString(cmd *exec.Cmd) string {
	if cmd == nil {
		return "<nil>"
	}
	return strings.TrimSpace(cmd.Path + " " + strings.Join(cmd.Args[1:], " "))
}
