//go:build linux

package kvm

import (
	"fmt"
	"os/exec"
	"sync"
	"syscall"

	"github.com/rs/zerolog"
)

type nativeOutput struct {
	mu     *sync.Mutex
	logger *zerolog.Event
}

func (w *nativeOutput) Write(p []byte) (n int, err error) {
	w.mu.Lock()
	defer w.mu.Unlock()

	w.logger.Msg(string(p))
	return len(p), nil
}

func startVideoBinary(binaryPath string) (*exec.Cmd, error) {
	// Run the binary inthe background
	cmd := exec.Command(binaryPath)

	vidoeOutputLock := sync.Mutex{}
	videoStdout := &nativeOutput{
		mu:     &vidoeOutputLock,
		logger: videoLogger.Info().Str("pipe", "stdout"),
	}
	videoStderr := &nativeOutput{
		mu:     &vidoeOutputLock,
		logger: videoLogger.Info().Str("pipe", "stderr"),
	}

	// Redirect stdout and stderr to the current process
	cmd.Stdout = videoStdout
	cmd.Stderr = videoStderr

	// Set the process group ID so we can kill the process and its children when this process exits
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid:   true,
		Pdeathsig: syscall.SIGKILL,
	}

	// Start the command
	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("failed to start binary: %w", err)
	}

	return cmd, nil
}

func startAudioBinary(binaryPath string) (*exec.Cmd, error) {
	// Run the binary inthe background
	cmd := exec.Command(binaryPath)

	audioOutputLock := sync.Mutex{}
	audioStdout := &nativeOutput{
		mu:     &audioOutputLock,
		logger: audioLogger.Info().Str("pipe", "stdout"),
	}
	audioStderr := &nativeOutput{
		mu:     &audioOutputLock,
		logger: audioLogger.Info().Str("pipe", "stderr"),
	}

	// Redirect stdout and stderr to the current process
	cmd.Stdout = audioStdout
	cmd.Stderr = audioStderr

	// Set the process group ID so we can kill the process and its children when this process exits
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid:   true,
		Pdeathsig: syscall.SIGKILL,
	}

	// Start the command
	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("failed to start binary: %w", err)
	}

	return cmd, nil
}

func startVpnBinary(binaryPath string) (*exec.Cmd, error) {
	// Run the binary inthe background
	cmd := exec.Command(binaryPath)

	vpnOutputLock := sync.Mutex{}
	vpnStdout := &nativeOutput{
		mu:     &vpnOutputLock,
		logger: audioLogger.Info().Str("pipe", "stdout"),
	}
	vpnStderr := &nativeOutput{
		mu:     &vpnOutputLock,
		logger: audioLogger.Info().Str("pipe", "stderr"),
	}

	// Redirect stdout and stderr to the current process
	cmd.Stdout = vpnStdout
	cmd.Stderr = vpnStderr

	// Set the process group ID so we can kill the process and its children when this process exits
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid:   true,
		Pdeathsig: syscall.SIGKILL,
	}

	// Start the command
	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("failed to start binary: %w", err)
	}

	return cmd, nil
}

func startDisplayBinary(binaryPath string) (*exec.Cmd, error) {
	// Run the binary inthe background
	cmd := exec.Command(binaryPath)

	displayOutputLock := sync.Mutex{}
	displayStdout := &nativeOutput{
		mu:     &displayOutputLock,
		logger: displayLogger.Info().Str("pipe", "stdout"),
	}
	displayStderr := &nativeOutput{
		mu:     &displayOutputLock,
		logger: displayLogger.Info().Str("pipe", "stderr"),
	}

	//// Redirect stdout and stderr to the current process
	cmd.Stdout = displayStdout
	cmd.Stderr = displayStderr

	// Set the process group ID so we can kill the process and its children when this process exits
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid:   true,
		Pdeathsig: syscall.SIGKILL,
	}

	// Start the command
	if err := cmd.Start(); err != nil {
		return nil, fmt.Errorf("failed to start binary: %w", err)
	}

	return cmd, nil
}
