//go:build linux

package client

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"golang.org/x/sys/unix"
)

// createSocketPair creates a Unix domain socket pair
func createSocketPair() ([2]int, error) {
	fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0)
	if err != nil {
		return [2]int{}, fmt.Errorf("socketpair: %w", err)
	}
	return fds, nil
}

func closeFDs(fds [2]int) {
	unix.Close(fds[0])
	unix.Close(fds[1])
}

func fdToFile(fd int, name string) *os.File {
	return os.NewFile(uintptr(fd), name)
}

// fixVHCIDevicePermissions waits for the VHCI-attached device to create
// device nodes (e.g. /dev/video*) and sets them to world-accessible.
// VHCI-created devices don't get normal udev rules applied, so they
// default to root-only access.
func fixVHCIDevicePermissions(port int) {
	// Wait for the device to finish enumerating and create device nodes.
	// The kernel needs time to enumerate descriptors and bind drivers.
	for attempt := 0; attempt < 15; attempt++ {
		time.Sleep(500 * time.Millisecond)

		found := false

		// Walk the VHCI sysfs tree to find device nodes at any depth.
		// Paths look like: vhci_hcd.0/usb3/3-1/3-1:1.0/video4linux/video0
		filepath.WalkDir("/sys/devices/platform/vhci_hcd.0", func(path string, d os.DirEntry, err error) error {
			if err != nil {
				return nil
			}

			dir := filepath.Dir(path)
			parent := filepath.Base(dir)

			// video4linux devices → /dev/videoN
			if parent == "video4linux" && strings.HasPrefix(d.Name(), "video") {
				devPath := "/dev/" + d.Name()
				if err := os.Chmod(devPath, 0666); err == nil {
					log.Printf("[use] set permissions 0666 on %s", devPath)
					found = true
				}
			}

			// sound devices → /dev/snd/*
			if parent == "sound" && strings.HasPrefix(d.Name(), "card") {
				// For sound cards, chmod all related device nodes
				sndDir := filepath.Join(path, "device")
				if _, err := os.Stat(sndDir); err == nil {
					filepath.WalkDir("/dev/snd", func(sndPath string, sd os.DirEntry, err error) error {
						if err == nil && !sd.IsDir() {
							os.Chmod(sndPath, 0666)
						}
						return nil
					})
				}
			}

			// input devices → /dev/input/eventN
			if strings.HasPrefix(d.Name(), "event") && strings.Contains(path, "/input/input") {
				devPath := "/dev/input/" + d.Name()
				if err := os.Chmod(devPath, 0666); err == nil {
					log.Printf("[use] set permissions 0666 on %s", devPath)
				}
			}

			return nil
		})

		if attempt >= 2 && found {
			return
		}
	}
}
