package vnc

import (
	"fmt"
	"github.com/cirruslabs/orchard/internal/proxy"
	"github.com/cirruslabs/orchard/pkg/client"
	"github.com/skratchdot/open-golang/open"
	"github.com/spf13/cobra"
	"net"
)

func newVNCWorkerCommand() *cobra.Command {
	command := &cobra.Command{
		Use:   "worker WORKER_NAME",
		Short: "Open VNC session with the worker",
		Args:  cobra.ExactArgs(1),
		RunE:  runVNCWorker,
	}

	command.Flags().StringVarP(&username, "username", "u", "",
		"VNC username")
	command.Flags().StringVarP(&password, "password", "p", "",
		"VNC password")
	return command
}

func runVNCWorker(cmd *cobra.Command, args []string) (err error) {
	name := args[0]

	client, err := client.New()
	if err != nil {
		return err
	}

	listener, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		return err
	}
	defer func() {
		if listenerErr := listener.Close(); listenerErr != nil && err == nil {
			err = listenerErr
		}
	}()

	fmt.Printf("forwarding %s -> %s:%d...\n", listener.Addr(), name, vncPort)

	errCh := make(chan error, 1)

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				errCh <- err

				return
			}

			go func() {
				wsConn, err := client.Workers().PortForward(cmd.Context(), name, vncPort)
				if err != nil {
					fmt.Printf("failed to forward port: %v\n", err)

					return
				}
				defer wsConn.Close()

				if err := proxy.Connections(wsConn, conn); err != nil {
					fmt.Printf("failed to forward port: %v\n", err)
				}
			}()
		}
	}()

	var credentialsComponent string
	var credentialsComponentSanitized string

	if username != "" {
		credentialsComponent = username
		credentialsComponentSanitized = username

		if password != "" {
			credentialsComponent += ":" + password
		}

		credentialsComponent += "@"
		credentialsComponentSanitized += "@"
	}

	openURL := fmt.Sprintf("vnc://%s%s", credentialsComponent, listener.Addr().String())
	openURLSanitized := fmt.Sprintf("vnc://%s%s", credentialsComponentSanitized, listener.Addr().String())

	fmt.Printf("opening %s...\n", openURLSanitized)

	if err := open.Start(openURL); err != nil {
		fmt.Printf("failed to open: %v\n", err)
	}

	select {
	case <-cmd.Context().Done():
		return cmd.Context().Err()
	case err := <-errCh:
		return err
	}
}
