package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/briandowns/spinner"
	"git.supernets.org/e/managerofmanagers/pkg_manager"
)

var (
	// Color definitions
	success = color.New(color.FgGreen, color.Bold)
	errorColor = color.New(color.FgRed, color.Bold)
	warning = color.New(color.FgYellow, color.Bold)
	info    = color.New(color.FgCyan)
	header  = color.New(color.FgMagenta, color.Bold)
	cmdColor = color.New(color.FgBlue, color.Bold)
	// Command line flags
	verbose bool
)

func showSpinner(message string) func() {
	s := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
	s.Suffix = " " + message
	s.Color("cyan")
	s.Start()
	return func() {
		s.Stop()
	}
}

func runWithSpinner(message string, needsSudo bool, fn func() error) error {
	var stop func()
	cmdStarted := make(chan struct{})
	
	if needsSudo {
		// Start a goroutine to show spinner after sudo auth
		go func() {
			<-cmdStarted
			fmt.Print("\r\033[K") // Clear the line
			stop = showSpinner(message)
		}()
	} else {
		stop = showSpinner(message)
	}
	
	err := fn()
	
	if needsSudo {
		close(cmdStarted)
		// Give the spinner a moment to show progress
		time.Sleep(500 * time.Millisecond)
	}
	
	if stop != nil {
		stop()
	}
	
	return err
}

func main() {
	// Initialize universal package managers
	pkg_manager.InitializeUniversalManagers()

	// Create custom flag set
	flags := flag.NewFlagSet("upm", flag.ExitOnError)
	flags.Usage = printUsage

	// Define flags
	var universalPM string
	flags.StringVar(&universalPM, "u", "", "Use universal package manager (snap/flatpak)")
	flags.BoolVar(&verbose, "v", false, "Show verbose output")

	// Find where the command starts (after flags)
	commandStart := 1
	for commandStart < len(os.Args) {
		if !strings.HasPrefix(os.Args[commandStart], "-") {
			break
		}
		commandStart++
	}

	// Parse only the flags before the command
	if err := flags.Parse(os.Args[1:commandStart]); err != nil {
		fmt.Fprintf(os.Stderr, "Error parsing flags: %v\n", err)
		os.Exit(1)
	}

	// Get command and its arguments (everything after the flags)
	if commandStart >= len(os.Args) {
		printUsage()
		os.Exit(1)
	}

	args := os.Args[commandStart:]

	if universalPM != "" {
		if mgr, ok := pkg_manager.GetUniversalManager(universalPM); ok {
			handleCommand(&mgr.Manager, args)
			return
		}
		fmt.Fprintf(os.Stderr, "Universal package manager %s not available\n", universalPM)
		os.Exit(1)
	}

	pm, err := pkg_manager.DetectPackageManager()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}

	handleCommand(pm, args)
}

func handleCommand(pm *pkg_manager.Manager, args []string) {
	// Set output mode based on verbose flag
	if verbose {
		pkg_manager.SetOutputMode(pkg_manager.OutputVerbose)
	} else {
		pkg_manager.SetOutputMode(pkg_manager.OutputQuiet)
	}

	if len(args) == 0 {
		printUsage()
		os.Exit(1)
	}

	command := args[0]
	// Filter out any arguments that look like flags
	var cmdArgs []string
	for _, arg := range args[1:] {
		if !strings.HasPrefix(arg, "-") {
			cmdArgs = append(cmdArgs, arg)
		}
	}

	switch command {
	case "install":
		if len(cmdArgs) == 0 {
			errorColor.Fprintln(os.Stderr, "Error: no packages specified")
			os.Exit(1)
		}
		err := runWithSpinner("Installing packages...", pm.NeedsSudo(), func() error {
			return pm.Install(cmdArgs...)
		})
		if err != nil {
			errorColor.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		success.Printf("āœ“ Successfully installed: %s\n", strings.Join(cmdArgs, ", "))

	case "remove":
		if len(cmdArgs) == 0 {
			errorColor.Fprintln(os.Stderr, "Error: no packages specified")
			os.Exit(1)
		}
		err := runWithSpinner("Removing packages...", pm.NeedsSudo(), func() error {
			return pm.Remove(cmdArgs...)
		})
		if err != nil {
			errorColor.Fprintf(os.Stderr, "Failed to remove packages: %v\n", err)
			os.Exit(1)
		}
		success.Printf("āœ“ Successfully removed: %s\n", strings.Join(cmdArgs, ", "))

	case "search":
		if len(cmdArgs) == 0 {
			fmt.Fprintln(os.Stderr, "Error: search term required")
			os.Exit(1)
		}
		if err := pm.Search(strings.Join(cmdArgs, " ")); err != nil {
			fmt.Fprintf(os.Stderr, "Search failed: %v\n", err)
			os.Exit(1)
		}

	case "update":
		if err := pm.Update(); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to update package lists: %v\n", err)
			os.Exit(1)
		}

	case "upgrade":
		if err := pm.Upgrade(); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to upgrade packages: %v\n", err)
			os.Exit(1)
		}

	case "list":
		if err := pm.ListInstalled(); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to list packages: %v\n", err)
			os.Exit(1)
		}

	case "info":
		if len(cmdArgs) == 0 {
			fmt.Fprintln(os.Stderr, "Error: package name required")
			os.Exit(1)
		}
		if err := pm.ShowInfo(cmdArgs[0]); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to show package info: %v\n", err)
			os.Exit(1)
		}

	case "repo":
		if len(cmdArgs) < 1 {
			fmt.Fprintln(os.Stderr, "Error: repo subcommand required (add/remove/list)")
			os.Exit(1)
		}
		switch cmdArgs[0] {
		case "add":
			if len(cmdArgs) < 2 {
				fmt.Fprintln(os.Stderr, "Error: repository URL required")
				os.Exit(1)
			}
			if err := pm.AddRepository(cmdArgs[1]); err != nil {
				fmt.Fprintf(os.Stderr, "Failed to add repository: %v\n", err)
				os.Exit(1)
			}
		case "remove":
			if len(cmdArgs) < 2 {
				fmt.Fprintln(os.Stderr, "Error: repository name required")
				os.Exit(1)
			}
			if err := pm.RemoveRepository(cmdArgs[1]); err != nil {
				fmt.Fprintf(os.Stderr, "Failed to remove repository: %v\n", err)
				os.Exit(1)
			}
		case "list":
			if err := pm.ListRepositories(); err != nil {
				fmt.Fprintf(os.Stderr, "Failed to list repositories: %v\n", err)
				os.Exit(1)
			}
		default:
			fmt.Fprintf(os.Stderr, "Unknown repo subcommand: %s\n", cmdArgs[0])
			printUsage()
			os.Exit(1)
		}

	case "clean":
		if err := pm.CleanCache(); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to clean cache: %v\n", err)
			os.Exit(1)
		}

	case "autoremove":
		if err := pm.AutoRemove(); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to remove unused dependencies: %v\n", err)
			os.Exit(1)
		}

	case "check-deps":
		pkg := ""
		if len(cmdArgs) > 0 {
			pkg = cmdArgs[0]
		}
		if err := pm.CheckDependencies(pkg); err != nil {
			fmt.Fprintf(os.Stderr, "Dependency check failed: %v\n", err)
			os.Exit(1)
		}

	case "show-deps":
		if len(cmdArgs) == 0 {
			fmt.Fprintln(os.Stderr, "Error: package name required")
			os.Exit(1)
		}
		if err := pm.ShowDependencies(cmdArgs[0]); err != nil {
			fmt.Fprintf(os.Stderr, "Failed to show dependencies: %v\n", err)
			os.Exit(1)
		}

	default:
		fmt.Fprintf(os.Stderr, "Unknown command: %s\n", command)
		printUsage()
		os.Exit(1)
	}
}

func printUsage() {
	header.Println("\nšŸ“¦ Universal Package Manager")
	fmt.Println("\nUsage: upm [-u snap|flatpak] [-v] <command> [arguments]")
	
	info.Println("\nCommands:")
	cmdColor.Print("  install ")
	fmt.Println("<package1[@version]> [package2[@version]...]  - Install packages")
	cmdColor.Print("  remove ")
	fmt.Println("<package1> [package2...]                       - Remove packages")
	cmdColor.Print("  search ")
	fmt.Println("<term>                                         - Search for packages")
	cmdColor.Print("  update ")
	fmt.Println("                                              - Update package lists")
	cmdColor.Print("  upgrade ")
	fmt.Println("                                             - Upgrade installed packages")
	cmdColor.Print("  list ")
	fmt.Println("                                                - List installed packages")
	cmdColor.Print("  info ")
	fmt.Println("<package>                                      - Show package information")
	
	info.Println("\nRepository Management:")
	cmdColor.Print("  repo add ")
	fmt.Println("<url>                                        - Add repository")
	cmdColor.Print("  repo remove ")
	fmt.Println("<name>                                     - Remove repository")
	cmdColor.Print("  repo list ")
	fmt.Println("                                          - List repositories")
	
	info.Println("\nMaintenance:")
	cmdColor.Print("  clean ")
	fmt.Println("                                              - Clean package cache")
	cmdColor.Print("  autoremove ")
	fmt.Println("                                         - Remove unused dependencies")
	
	info.Println("\nDependency Management:")
	cmdColor.Print("  check-deps ")
	fmt.Println("[package]                                - Check dependencies")
	cmdColor.Print("  show-deps ")
	fmt.Println("<package>                                - Show package dependencies")
	
	info.Println("\nFlags:")
	fmt.Println("  -u string    Use universal package manager (snap/flatpak)")
	fmt.Println("  -v          Show verbose output")

	warning.Println("\nExamples:")
	fmt.Println("  upm install nginx@1.18.0")
	fmt.Println("  upm -u snap install firefox")
	fmt.Println("  upm repo add https://repo.example.com")
	fmt.Println("  upm show-deps nginx")
	fmt.Println()
}