package cluster

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"os/exec"

	"github.com/pomerium/pomerium/internal/log"
)

type cmdOption func(*exec.Cmd)

func withArgs(args ...string) cmdOption {
	return func(cmd *exec.Cmd) {
		cmd.Args = append([]string{"kubectl"}, args...)
	}
}

func withEnv(env ...string) cmdOption {
	return func(cmd *exec.Cmd) {
		cmd.Env = append(os.Environ(), env...)
	}
}

func withStdin(rdr io.Reader) cmdOption {
	return func(cmd *exec.Cmd) {
		cmd.Stdin = rdr
	}
}

func withStdout(w io.Writer) cmdOption {
	return func(cmd *exec.Cmd) {
		cmd.Stdout = w
	}
}

func withWorkingDir(wd string) cmdOption {
	return func(cmd *exec.Cmd) {
		cmd.Dir = wd
	}
}

func run(ctx context.Context, name string, options ...cmdOption) error {
	cmd := commandContext(ctx, name)
	for _, o := range options {
		o(cmd)
	}
	if cmd.Stderr == nil {
		stderr, err := cmd.StderrPipe()
		if err != nil {
			return fmt.Errorf("failed to create stderr pipe for %s: %w", name, err)
		}
		go cmdLogger(ctx, stderr)
		defer stderr.Close()
	}
	if cmd.Stdout == nil {
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			return fmt.Errorf("failed to create stdout pipe for %s: %w", name, err)
		}
		go cmdLogger(ctx, stdout)
		defer stdout.Close()
	}

	log.Debug(ctx).Strs("args", cmd.Args).Msgf("running %s", name)
	return cmd.Run()
}

func cmdLogger(ctx context.Context, rdr io.Reader) {
	s := bufio.NewScanner(rdr)
	for s.Scan() {
		log.Debug(ctx).Msg(s.Text())
	}
}