package main

import (
	"embed"
	"flag"
	"io/fs"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"imuslab.com/remdeskvm/remdeskd/mod/remdeshid"
	"imuslab.com/remdeskvm/remdeskd/mod/usbcapture"
)

const defaultDevMode = true

var (
	developent        = flag.Bool("dev", defaultDevMode, "Enable development mode with local static files")
	mode              = flag.String("mode", "usbkvm", "Mode of operation: kvm or capture")
	usbKVMDeviceName  = flag.String("usbkvm", "/dev/ttyUSB0", "USB KVM device file path")
	usbKVMBaudRate    = flag.Int("baudrate", 115200, "USB KVM baud rate")
	captureDeviceName = flag.String("capture", "/dev/video0", "Video capture device file path")
	usbKVM            *remdeshid.Controller
	videoCapture      *usbcapture.Instance
)

/* Web Server Static Files */
//go:embed www
var embeddedFiles embed.FS
var webfs http.FileSystem

func init() {
	// Initiate the web server static files
	if *developent {
		webfs = http.Dir("./www")
	} else {
		// Embed the ./www folder and trim the prefix
		subFS, err := fs.Sub(embeddedFiles, "www")
		if err != nil {
			log.Fatal(err)
		}
		webfs = http.FS(subFS)
	}
}

func main() {
	flag.Parse()
	// Initiate the HID controller
	usbKVM = remdeshid.NewHIDController(&remdeshid.Config{
		PortName:          *usbKVMDeviceName,
		BaudRate:          *usbKVMBaudRate,
		ScrollSensitivity: 0x01, // Set mouse scroll sensitivity
	})
	switch *mode {
	case "cfgchip":
		//Start the HID controller
		err := usbKVM.Connect()
		if err != nil {
			log.Fatal(err)
		}

		time.Sleep(1 * time.Second) // Wait for the controller to initialize
		log.Println("Updating chip baudrate to 115200...")
		//Configure the HID controller
		err = usbKVM.ConfigureChipTo115200()
		if err != nil {
			log.Fatalf("Failed to configure chip baudrate: %v", err)
			return
		}
		time.Sleep(1 * time.Second)

		log.Println("Setting chip USB device properties...")
		time.Sleep(2 * time.Second) // Wait for the controller to initialize
		_, err = usbKVM.WriteChipProperties()
		if err != nil {
			log.Fatalf("Failed to write chip properties: %v", err)
			return
		}

		log.Println("Configuration command sent. Unplug the device and plug it back in to apply the changes.")
	case "usbkvm":

		log.Println("Starting in USB KVM mode...")

		//Start the HID controller
		err := usbKVM.Connect()
		if err != nil {
			log.Fatal(err)
		}

		// Initiate the video capture device
		videoCapture, err = usbcapture.NewInstance(&usbcapture.Config{
			DeviceName:  *captureDeviceName,
			AudioConfig: usbcapture.GetDefaultAudioConfig(),
		})

		if err != nil {
			log.Fatalf("Failed to create video capture instance: %v", err)
		}

		//Get device information for debug
		usbcapture.PrintV4L2FormatInfo(*captureDeviceName)

		//Start the video capture device
		err = videoCapture.StartVideoCapture(&usbcapture.CaptureResolution{
			Width:  1920,
			Height: 1080,
			FPS:    10,
		})
		if err != nil {
			log.Fatal(err)
		}

		// Handle program exit to close the HID controller

		c := make(chan os.Signal, 1)
		signal.Notify(c, os.Interrupt, syscall.SIGTERM)
		go func() {
			<-c
			log.Println("Shutting down usbKVM...")
			//usbKVM.Close() //To fix close stuck layer
			log.Println("Shutting down capture device...")
			videoCapture.Close()
			os.Exit(0)
		}()

		// Start the web server
		http.Handle("/", http.FileServer(webfs))
		http.HandleFunc("/hid", usbKVM.HIDWebSocketHandler)
		http.HandleFunc("/audio", videoCapture.AudioStreamingHandler)
		http.HandleFunc("/stream", videoCapture.ServeVideoStream)
		addr := ":9000"
		log.Printf("Serving on http://localhost%s\n", addr)
		log.Fatal(http.ListenAndServe(addr, nil))
	case "list-audio-devices":
		log.Println("Starting in List Audio Devices mode...")
		//Get the audio devices
		path, err := usbcapture.FindHDMICapturePCMPath()
		if err != nil {
			log.Fatalf("Failed to find HDMI capture PCM path: %v", err)
		}
		log.Printf("Found HDMI capture PCM path: %s\n", path)
		//List all audio capture devices
		captureDevs, err := usbcapture.ListCaptureDevices()
		if err != nil {
			log.Fatalf("Failed to list capture devices: %v", err)
		}
		log.Println("Available audio capture devices:")
		for _, dev := range captureDevs {
			log.Printf(" - %s\n", dev)
		}

	default:
		log.Fatalf("Unknown mode: %s. Supported modes are: usbkvm, capture", *mode)
	}
}
