## NimPak CLI - Next-generation package manager for NexusOS
##
## Main entry point for the `nip` command-line tool.
## Provides atomic, reproducible package management with ACUL compliance.

import std/[os, strformat, strutils, posix, asyncdispatch, tables, sequtils]
import nimpak/cli/[core, commands, enhanced_search, diagnostics_commands, setup_commands]
import nimpak/cli/help
import nimpak/cli/graft_commands as graft # Variant system integration
import nimpak/cli/build_commands as build # Source building with variants
import nimpak/cli/variant_switch # Variant switching commands
import nimpak/cli/bootstrap_commands # Build tool bootstrap

# import nip/doctor
# import nip/cli/resolve_command # Dependency resolution commands
import nimpak/config
# import nip/[manifest_parser, archives, nip_installer, namespace, cas, types]

const
  NimPakVersion = "0.1.0"
  NimPakBanner = """
🌱 NimPak v$1 - Universal Package Manager for NexusOS
   Atomic • Reproducible • ACUL Compliant • 205,000+ Packages
""" % [NimPakVersion]

proc showConfigCommand(): CommandResult =
  ## Show current configuration
  let config = loadConfig()
  let output = fmt"""
Current Configuration:
  Programs Dir: {config.programsDir}
  Links Dir: {config.linksDir}
  Cache Dir: {config.cacheDir}
  Active Profile: {config.activeProfile}
  Adapters: {config.adapters.len} enabled
  Variant Targets: {config.defaultTarget}
  """
  return successResult(output)

proc initConfigCommand(): CommandResult =
  ## Initialize default configuration
  try:
    initDefaultConfig()
    return successResult(fmt"Initialized default configuration at {getConfigPath()}")
  except Exception as e:
    return errorResult(fmt"Failed to initialize configuration: {e.msg}")
proc dispatchCommand(args: seq[string]): int =
  ## Main command dispatcher with advanced CLI features
  if args.len == 0:
    showMainHelp()
    return 0

  # Parse global options
  let (globalOptions, remainingArgs) = parseGlobalOptions(args)
  discard initCliContext(globalOptions)

  if remainingArgs.len == 0:
    showMainHelp()
    return 0

  let command = remainingArgs[0].toLower()
  let commandArgs = remainingArgs[1..^1]

  # Check PATH configuration (except for setup command itself)
  if command != "setup" and not checkPathConfigured():
    echo "⚠️  NIP binary path is NOT in your PATH."
    echo "   Run `nip setup user` to automatically configure your shell."
    echo ""

  var commandRes: CommandResult

  try:
    case command:
    # Core package management commands
    of "install":
      if commandArgs.len == 0:
        commandRes = errorResult("Usage: nip install <package> [options]")
      else:
        let target = commandArgs[0]
        if target.endsWith(".nip"):
           commandRes = errorResult("Local NIP installation not yet migrated")
        else:
           let verbose = globalOptions.verbose
           # Map 'install' to 'graft' for now as per MVP
           let exitCode = graft.graftCommand(target, verbose)
           commandRes = if exitCode == 0: successResult("Package installed") else: errorResult("Install failed")

    of "remove":
      if commandArgs.len == 0:
        commandRes = errorResult("Usage: nip remove <package>")
      else:
        let verbose = globalOptions.verbose
        let exitCode = graft.removeCommand(commandArgs[0], verbose)
        commandRes = if exitCode == 0: successResult("Package removed") else: errorResult("Failed to remove package")

    of "update":
       commandRes = errorResult("Update command not yet implemented")

    of "setup":
       commandRes = setup_commands.setupCommand(commandArgs)

    of "search":
      if commandArgs.len == 0:
        commandRes = errorResult("Usage: nip search <query>")
      else:
        # Check for --remote flag manually if needed, or pass all args
        let queryArgs = commandArgs.filterIt(it != "--remote")
        let query = queryArgs.join(" ")
        commandRes = enhanced_search.enhancedSearchCommand(query)

    # Variant & Graft commands
    of "graft":
      if commandArgs.len == 0:
        commandRes = errorResult("Usage: nip graft <package>")
      else:
        let verbose = globalOptions.verbose
        let exitCode = graft.graftCommand(commandArgs[0], verbose)
        commandRes = if exitCode == 0: successResult("Graft complete") else: errorResult("Graft failed")

    of "switch":
      if commandArgs.len < 2:
        commandRes = errorResult("Usage: nip switch <package> <variant>")
      else:
        let exitCode = variant_switch.switchCommand(commandArgs[0], commandArgs[1])
        commandRes = if exitCode == 0: successResult("Switch complete") else: errorResult("Switch failed")

    of "build":
      if commandArgs.len == 0:
        commandRes = errorResult("Usage: nip build <package> [flags]")
      else:
        let pkg = commandArgs[0]
        let flags = if commandArgs.len > 1: commandArgs[1..^1] else: @[]
        let verbose = globalOptions.verbose
        let exitCode = build.buildCommand(pkg, flags, "auto", verbose)
        commandRes = if exitCode == 0: successResult("Build complete") else: errorResult("Build failed")

    of "bootstrap":
      if commandArgs.len == 0:
        commandRes = errorResult("Usage: nip bootstrap <list|install|remove|info> ...")
      else:
        let subCmd = commandArgs[0].toLower()
        let exitCode = case subCmd
          of "list": bootstrap_commands.bootstrapListRecipesCommand()
          of "install": 
            if commandArgs.len > 1: bootstrap_commands.bootstrapInstallCommand(commandArgs[1]) else: 1
          of "remove":
            if commandArgs.len > 1: bootstrap_commands.bootstrapRemoveCommand(commandArgs[1]) else: 1
          of "info":
            if commandArgs.len > 1: bootstrap_commands.bootstrapInfoCommand(commandArgs[1]) else: 1
          of "recipes": bootstrap_commands.bootstrapListRecipesCommand()
          of "update-recipes": bootstrap_commands.bootstrapUpdateRecipesCommand()
          of "help": 
             bootstrap_commands.bootstrapHelpCommand()
             0
          else: 1
        
        commandRes = if exitCode == 0: successResult("Bootstrap command successful") else: errorResult("Bootstrap command failed")

    # Cell Management
    of "cell":
        commandRes = errorResult("Cell commands not fully implemented in this dispatch")

    # App / Nexter / GC / CAS stubs
    of "app", "nexter", "gc", "cas":
       commandRes = successResult(fmt"Command '{command}' is a placeholder in this MVP")

    # Reproducibility commands
    of "lock":
      commandRes = lockCommand()

    of "restore":
       if commandArgs.len == 0:
         commandRes = errorResult("Usage: nip restore <lockfile>")
       else:
         commandRes = restoreCommand(commandArgs[0])

    of "diff":
      commandRes = diffCommand()

    # Verification commands
    of "verify":
      commandRes = enhanced_search.verifyCommand(commandArgs)

    of "diagnose":
       if commandArgs.len == 0:
         commandRes = errorResult("Usage: nip diagnose <cid>")
       else:
         commandRes = enhanced_search.diagnoseCommand(commandArgs)

    # Doctor/health check commands
    of "doctor":
      let autoRepair = "--fix" in commandArgs or "--auto" in commandArgs
      let outputFormat = if "--json" in commandArgs: "json" else: "plain"
      let report = waitFor diagnostics_commands.nipDoctor(outputFormat, autoRepair)
      echo report
      commandRes = successResult("System health check completed")

    # Configuration commands
    of "config":
      if commandArgs.len == 0:
         commandRes = errorResult("Usage: nip config <show|init|path>")
      else:
         case commandArgs[0].toLower():
         of "show": commandRes = showConfigCommand()
         of "init": commandRes = initConfigCommand()
         of "path": commandRes = successResult(getConfigPath())
         else: commandRes = errorResult("Unknown config command")

    of "resolve":
      commandRes = errorResult("Resolve command not yet migrated")

    of "explain":
      commandRes = errorResult("Explain command not yet migrated")

    # Help commands
    of "help", "--help", "-h":
      if commandArgs.len > 0:
        showCommandHelp(commandArgs[0])
      else:
        showMainHelp()
      return 0
      
    of "version", "--version", "-v":
      echo NimPakBanner
      return 0

    else:
      commandRes = errorResult(fmt"Unknown command: {command}")

  except Exception as e:
    commandRes = errorResult(fmt"Unexpected error: {e.msg}")

  # Output result
  if not commandRes.success:
    echo fmt"❌ Error: {commandRes.message}"
    return 1
  else:
    if commandRes.message != "":
      echo commandRes.message
    return 0



# =============================================================================
# Main Entry Point
# =============================================================================

when isMainModule:
  let args = commandLineParams()
  let exitCode = dispatchCommand(args)
  quit(exitCode)
