package service

import (
	"context"
	"fmt"
	"os/exec"
	"strings"

	"github.com/qdm12/gluetun/internal/command"
)

func runCommand(ctx context.Context, cmder Cmder, logger Logger,
	commandTemplate string, ports []uint16, vpnInterface string,
) (err error) {
	portStrings := make([]string, len(ports))
	for i, port := range ports {
		portStrings[i] = fmt.Sprint(int(port))
	}
	portsString := strings.Join(portStrings, ",")
	commandString := strings.ReplaceAll(commandTemplate, "{{PORTS}}", portsString)
	commandString = strings.ReplaceAll(commandString, "{{PORT}}", portStrings[0])
	commandString = strings.ReplaceAll(commandString, "{{VPN_INTERFACE}}", vpnInterface)
	args, err := command.Split(commandString)
	if err != nil {
		return fmt.Errorf("parsing command: %w", err)
	}

	cmd := exec.CommandContext(ctx, args[0], args[1:]...) // #nosec G204
	stdout, stderr, waitError, err := cmder.Start(cmd)
	if err != nil {
		return err
	}

	streamCtx, streamCancel := context.WithCancel(context.Background())
	streamDone := make(chan struct{})
	go streamLines(streamCtx, streamDone, logger, stdout, stderr)

	err = <-waitError
	streamCancel()
	<-streamDone
	return err
}

func streamLines(ctx context.Context, done chan<- struct{},
	logger Logger, stdout, stderr <-chan string,
) {
	defer close(done)

	var line string

	for {
		select {
		case <-ctx.Done():
			return
		case line = <-stdout:
			logger.Info(line)
		case line = <-stderr:
			logger.Error(line)
		}
	}
}
