package launcher

import (
	"bufio"
	"epochsilicon/pkg/log"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"sync"

	"epochsilicon/pkg/paths" // Corrected import path
	"epochsilicon/pkg/utils" // Corrected import path

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/dialog"
)

var EnableMetalHud = false // Default to disabled
var CustomEnvVars = ""     // Custom environment variables
var AutoDeleteWdb = false  // Default to disabled

// Terminal state management
var (
	currentGameProcess *exec.Cmd
	isGameRunning      bool
	gameMutex          sync.Mutex
)

// runGameIntegrated runs the game with integrated terminal output
func runGameIntegrated(parentWindow fyne.Window, shellCmd string) error {
	gameMutex.Lock()
	defer gameMutex.Unlock()

	if isGameRunning {
		return fmt.Errorf("game is already running")
	}

	isGameRunning = true

	// Parse the shell command to extract components
	// The shellCmd format is: cd <path> && <envVars> <rosettaExec> <wineloader> <wowExe>
	log.Debugf("Parsing shell command: %s", shellCmd)

	// Create the command without context cancellation
	cmd := exec.Command("sh", "-c", shellCmd)

	// Set up stdout and stderr pipes
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		isGameRunning = false
		return err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		isGameRunning = false
		return err
	}

	currentGameProcess = cmd

	// Start the process
	if err := cmd.Start(); err != nil {
		isGameRunning = false
		return err
	}

	// Monitor output in goroutines
	go func() {
		scanner := bufio.NewScanner(stdout)
		for scanner.Scan() {
			line := scanner.Text()
			log.WineLoggerStdout(line)
		}
	}()

	go func() {
		scanner := bufio.NewScanner(stderr)
		for scanner.Scan() {
			line := scanner.Text()
			log.WineLoggerStderr(line)
		}
	}()

	// Wait for the process to complete in a goroutine
	go func() {
		defer func() {
			gameMutex.Lock()
			isGameRunning = false
			currentGameProcess = nil
			gameMutex.Unlock()
		}()

		if err := cmd.Wait(); err != nil {
			log.Debugf("Game process ended with error: %v", err)
		} else {
			log.Debug("Game process ended successfully")
		}
	}()

	return nil
}

func LaunchGame(myWindow fyne.Window) {
	log.Debug("Launch Game button clicked")

	if paths.CrossoverPath == "" {
		dialog.ShowError(fmt.Errorf("CrossOver path not set. Please set it in the patcher."), myWindow)
		return
	}
	if paths.EpochPath == "" {
		dialog.ShowError(fmt.Errorf("Epoch path not set. Please set it in the patcher."), myWindow)
		return
	}
	if !paths.PatchesAppliedEpoch || !paths.PatchesAppliedCrossOver {
		confirmed := false
		dialog.ShowConfirm("Warning", "Not all patches confirmed applied. Continue with launch?", func(c bool) {
			confirmed = c
		}, myWindow)
		if !confirmed {
			return
		}
	}

	// Check if game is already running
	gameMutex.Lock()
	if isGameRunning {
		gameMutex.Unlock()
		dialog.ShowInformation("Game Already Running", "The game is already running.", myWindow)
		return
	}
	gameMutex.Unlock()

	log.Debug("Preparing to launch EpochSilicon...")

	wowExePath := filepath.Join(paths.EpochPath, "Project-Epoch.exe")

	// Continue with normal launch process
	continueLaunch(myWindow, wowExePath)
}

// continueLaunch continues the game launch process with the specified executable
func continueLaunch(myWindow fyne.Window, wowExePath string) {
	rosettaInEpochPath := filepath.Join(paths.EpochPath, "rosettax87")
	rosettaExecutable := filepath.Join(rosettaInEpochPath, "rosettax87")
	wineloader2Path := filepath.Join(paths.CrossoverPath, "Contents", "SharedSupport", "CrossOver", "CrossOver-Hosted Application", "wineloader2")

	if !utils.PathExists(rosettaExecutable) {
		dialog.ShowError(fmt.Errorf("rosetta executable not found at %s. Ensure Epoch patching was successful", rosettaExecutable), myWindow)
		return
	}
	if !utils.PathExists(wineloader2Path) {
		dialog.ShowError(fmt.Errorf("patched wineloader2 not found at %s. Ensure CrossOver patching was successful", wineloader2Path), myWindow)
		return
	}
	if !utils.PathExists(wowExePath) {
		dialog.ShowError(fmt.Errorf("WoW executable not found at %s. Ensure your Epoch directory is correct", wowExePath), myWindow)
		return
	}

	// Auto-delete WDB directory if enabled
	if AutoDeleteWdb {
		wdbPath := filepath.Join(paths.EpochPath, "WDB")
		if utils.DirExists(wdbPath) {
			log.Debugf("Auto-deleting WDB directory: %s", wdbPath)
			if err := os.RemoveAll(wdbPath); err != nil {
				log.Debugf("Warning: failed to auto-delete WDB directory: %v", err)
				// Don't block the launch, just log the error
			} else {
				log.Debugf("Successfully auto-deleted WDB directory")
			}
		} else {
			log.Debugf("WDB directory not found, nothing to delete")
		}
	}

	// Since RosettaX87 service is already running, we can directly launch WoW
	log.Debug("RosettaX87 service is running. Proceeding to launch WoW.")

	if paths.CrossoverPath == "" || paths.EpochPath == "" {
		dialog.ShowError(fmt.Errorf("CrossOver path or Epoch path is not set. Cannot launch WoW."), myWindow)
		return
	}

	mtlHudValue := "0"
	if EnableMetalHud {
		mtlHudValue = "1"
	}

	// Prepare environment variables
	envVars := fmt.Sprintf(`WINEDLLOVERRIDES="d3d9=n,b" MTL_HUD_ENABLED=%s DXVK_ASYNC=1`, mtlHudValue)
	if CustomEnvVars != "" {
		envVars = CustomEnvVars + " " + envVars
	}

	shellCmd := fmt.Sprintf(`cd %s && %s %s %s %s`,
		utils.QuotePathForShell(paths.EpochPath),
		envVars,
		utils.QuotePathForShell(rosettaExecutable),
		utils.QuotePathForShell(wineloader2Path),
		utils.QuotePathForShell(wowExePath))

	// Use integrated terminal
	log.Debugf("Shell command for integrated terminal: %s", shellCmd)
	log.Debug("Executing WoW launch command with integrated terminal...")
	if err := runGameIntegrated(myWindow, shellCmd); err != nil {
		dialog.ShowError(fmt.Errorf("failed to launch game: %v", err), myWindow)
		return
	}
}

// IsGameRunning returns true if the game is currently running
func IsGameRunning() bool {
	gameMutex.Lock()
	defer gameMutex.Unlock()
	return isGameRunning
}

// StopGame forcefully stops the running game
func StopGame() error {
	gameMutex.Lock()
	defer gameMutex.Unlock()

	if !isGameRunning || currentGameProcess == nil {
		return fmt.Errorf("no game process is running")
	}

	// Try to terminate gracefully first
	if err := currentGameProcess.Process.Signal(os.Interrupt); err != nil {
		// If that fails, force kill
		return currentGameProcess.Process.Kill()
	}

	return nil
}
