package spitfire

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

// Array to store errors
var errors []string

// SetGlobalEnv sets the MOZILLABUILD environment variable globally for the user (or system)
func SetGlobalEnv(variable, value string, scope string) error {
	if runtime.GOOS == "windows" {
		var cmd *exec.Cmd
		if scope == "user" {
			cmd = exec.Command("setx", variable, value) // Set for current user
		} else if scope == "system" {
			cmd = exec.Command("setx", variable, value, "/M") // Set for system (requires admin privileges)
		} else {
			return fmt.Errorf("unknown scope: %s", scope)
		}

		// Run the command
		out, err := cmd.CombinedOutput()
		if err != nil {
			return fmt.Errorf("failed to set environment variable %s=%s: %v\nOutput: %s", variable, value, err, string(out))
		}
		fmt.Printf("Successfully set %s=%s\n", variable, value)
		return nil
	} else {
		return fmt.Errorf("global environment variable setting is not supported on non-Windows systems")
	}
}

// Run an external command like scp or rsync
func runCommand(command string, args ...string) error {
	cmd := exec.Command(command, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// Function to resolve paths using absolute path
func ResolvePath(path string) (string, error) {
	// Convert Unix-style slashes to the platform's native slashes
	path = filepath.FromSlash(path)

	// Get the absolute path
	absPath, err := filepath.Abs(path)
	if err != nil {
		return "", fmt.Errorf("failed to resolve path: %s, error: %v", path, err)
	}
	return absPath, nil
}

// Function to download Mozilla source if not present
func DownloadSource(sourcePath string, sourceRepo string) {
	if _, err := os.Stat(sourcePath); os.IsNotExist(err) {
		fmt.Println("Mozilla source not found. Cloning from repository...")
		if err := runCommand("hg", "clone", sourceRepo, sourcePath); err != nil {
			errors = append(errors, "Failed to clone Mozilla repository.")
		}
	} else {
		fmt.Println("Mozilla source already exists.")
	}
}

// Function to discard uncommitted changes
func DiscardChanges(sourcePath string) {
	fmt.Println("Discarding uncommitted changes...")
	if err := runCommand("hg", "revert", "--all", "--no-backup", "-R", sourcePath); err != nil {
		errors = append(errors, "Failed to revert changes in Mozilla repository.")
	}
}

// Function to clean build
func CleanBuild(sourcePath string) {
	fmt.Println("Cleaning build...")
	if err := os.Chdir(sourcePath); err != nil {
		errors = append(errors, "Failed to navigate to source directory.")
		return
	}
	if err := runCommand("hg", "revert", "--all", "--no-backup"); err != nil {
		errors = append(errors, "Failed to revert changes in Mozilla repository.")
	}
	if err := runCommand("./mach", "clobber"); err != nil {
		errors = append(errors, "Failed to clean build.")
	}
}

// Function to update Mozilla repository
func UpdateRepo(sourcePath string) {
	fmt.Println("Updating Mozilla repository...")
	if err := os.Chdir(sourcePath); err != nil {
		errors = append(errors, "Failed to navigate to source directory.")
		return
	}
	if err := runCommand("hg", "pull", "-u"); err != nil {
		errors = append(errors, "Failed to update Mozilla repository.")
	}
}

// Function to update patches
func UpdatePatches(patchesDir, patchesRepo, sourcePath string) {
	fmt.Println("Updating patches...")
	if _, err := os.Stat(patchesDir); err == nil {
		fmt.Println("Patches directory already exists. Cleaning and pulling updates...")
		if err := os.Chdir(patchesDir); err != nil {
			errors = append(errors, "Failed to navigate to patches directory.")
			return
		}
		if err := runCommand("git", "clean", "-xdf"); err != nil {
			errors = append(errors, "Failed to clean patches directory.")
		}
		_ = runCommand("git", "stash", "push", "--include-untracked")
		if err := runCommand("git", "fetch"); err != nil {
			errors = append(errors, "Failed to fetch updates from patches repository.")
		}
		if runCommand("git", "show-ref", "--verify", "--quiet", "refs/heads/main") == nil {
			if err := runCommand("git", "rebase", "origin/main"); err != nil {
				errors = append(errors, "Failed to rebase updates from main branch.")
			}
		} else if runCommand("git", "show-ref", "--verify", "--quiet", "refs/heads/master") == nil {
			if err := runCommand("git", "rebase", "origin/master"); err != nil {
				errors = append(errors, "Failed to rebase updates from master branch.")
			}
		} else {
			errors = append(errors, "No valid branch (main or master) found in patches repository.")
			return
		}
		if runCommand("git", "stash", "list") == nil {
			_ = runCommand("git", "stash", "pop")
		} else {
			fmt.Println("No stash entries found, skipping pop.")
		}
	} else {
		fmt.Println("Patches directory does not exist. Cloning repository...")
		if err := runCommand("git", "clone", patchesRepo, patchesDir); err != nil {
			errors = append(errors, "Failed to clone patches repository.")
		}
	}

	// Handle platform-specific rsync command
	fmt.Println("Copying files from patches directory to Firefox source directory...")
	if runtime.GOOS == "windows" {
		// Use robocopy for Windows instead of rsync
		if err := runCommand("robocopy", patchesDir, sourcePath, "/MIR"); err != nil {
			errors = append(errors, "Failed to copy files (Windows robocopy).")
		}
	} else {
		// Use rsync for Unix-like systems
		if err := runCommand("rsync", "-av", "--exclude=.git", patchesDir+"/", sourcePath+"/"); err != nil {
			errors = append(errors, "Failed to copy files (rsync).")
		}
	}
}

// Function to configure Spitfire
func Configure(sourcePath string) {
	fmt.Println("Configuring Spitfire...")
	if err := os.Chdir(sourcePath); err != nil {
		errors = append(errors, "Failed to navigate to source directory.")
		return
	}
	if err := runCommand("./mach", "configure"); err != nil {
		errors = append(errors, "Configuration failed.")
	}
}

// Function to build Spitfire
func Build(sourcePath string) {
	fmt.Println("Building Spitfire...")
	if err := os.Chdir(sourcePath); err != nil {
		errors = append(errors, "Failed to navigate to source directory.")
		return
	}
	if err := runCommand("./mach", "build"); err != nil {
		errors = append(errors, "Build failed.")
	}
}

// Function to run the project after build
func RunProject(sourcePath string) {
	fmt.Println("Running the project...")
	if err := os.Chdir(sourcePath); err != nil {
		errors = append(errors, "Failed to navigate to source directory.")
		return
	}
	if err := runCommand("./mach", "run"); err != nil {
		errors = append(errors, "Failed to run the project.")
	}
}

// Function to print collected errors
func PrintErrors() {
	if len(errors) > 0 {
		fmt.Println("The following errors occurred during execution:")
		for _, err := range errors {
			fmt.Printf("- %s\n", err)
		}
	}
}