package main

import (
	"fmt"
	"os"
	"os/exec"
	"qvm/internal/config"
	"qvm/internal/logging"
	"qvm/internal/vm"
	"qvm/internal/workspace"
	"strconv"
	"strings"

	"github.com/spf13/cobra"
	"golang.org/x/term"
)

var runCmd = &cobra.Command{
	Use:   "run <command> [args...]",
	Short: "Run a command in the VM workspace",
	Long: `Execute a command in the VM at the current directory.

The current directory is automatically registered as a workspace
and mounted into the VM. The command runs in the mounted workspace.`,
	Args: cobra.MinimumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		cwd, err := os.Getwd()
		if err != nil {
			logging.Error(fmt.Sprintf("Failed to get current directory: %v", err))
			os.Exit(1)
		}

		regResult := workspace.Load(config.WorkspacesFile)
		if regResult.IsError() {
			logging.Error(regResult.Error().Error())
			os.Exit(1)
		}
		reg := regResult.MustGet()

		wsResult := reg.Register(cwd)
		if wsResult.IsError() {
			logging.Error(wsResult.Error().Error())
			os.Exit(1)
		}
		ws := wsResult.MustGet()

		saveResult := reg.Save()
		if saveResult.IsError() {
			logging.Error(saveResult.Error().Error())
			os.Exit(1)
		}

		wasRunning := vm.IsRunning()

		if !wasRunning {
			logging.Info("VM is not running, starting it...")
			cfg, err := config.Load()
			if err != nil {
				logging.Error(err.Error())
				os.Exit(1)
			}

			startResult := vm.Start(cfg, reg)
			if startResult.IsError() {
				logging.Error(startResult.Error().Error())
				os.Exit(1)
			}
		}

		statusResult := vm.Status()
		if statusResult.IsError() {
			logging.Error(statusResult.Error().Error())
			os.Exit(1)
		}
		status := statusResult.MustGet()

		remoteCmd := fmt.Sprintf("mkdir -p '%s' && mount -t 9p ws_%s '%s' -o trans=virtio,version=9p2000.L,msize=104857600 2>/dev/null || true && cd '%s' && %s", 
			ws.GuestPath, ws.Hash, ws.GuestPath, ws.GuestPath, strings.Join(args, " "))

		sshArgs := []string{
			"-p", "root",
			"ssh",
			"-o", "StrictHostKeyChecking=no",
			"-o", "UserKnownHostsFile=/dev/null",
			"-o", "LogLevel=ERROR",
		}

		// Allocate TTY for interactive commands
		if term.IsTerminal(int(os.Stdin.Fd())) {
			sshArgs = append(sshArgs, "-t")
		}

		sshArgs = append(sshArgs,
			"-p", strconv.Itoa(status.SSHPort),
			"root@localhost",
			remoteCmd,
		)

		sshpassCmd := exec.Command("sshpass", sshArgs...)
		sshpassCmd.Stdin = os.Stdin
		sshpassCmd.Stdout = os.Stdout
		sshpassCmd.Stderr = os.Stderr

		if err := sshpassCmd.Run(); err != nil {
			if exitErr, ok := err.(*exec.ExitError); ok {
				os.Exit(exitErr.ExitCode())
			}
			os.Exit(1)
		}
	},
}
