# nimpak/cli/graft.nim
# CLI commands for package grafting

import std/[strutils, json, os, tables, sequtils]
import ../../nip/types
import ../grafting
import ../adapters/pacman
import ../adapters/nix
import ../adapters/pkgsrc

type
  GraftCommand* = object
    source*: string
    packageName*: string
    convert*: bool
    verify*: bool
    output*: string  # json, yaml, kdl, or human

  GraftStatusCommand* = object
    output*: string
    verbose*: bool

  GraftConvertCommand* = object
    packageName*: string
    outputPath*: string
    verify*: bool

proc executeGraftCommand*(cmd: GraftCommand): int =
  ## Execute nip graft <source> <package> command
  echo "🌱 Grafting package: " & cmd.packageName & " from " & cmd.source

  try:
    # Initialize grafting engine
    let engineResult = initGraftingEngine()
    if engineResult.isErr:
      echo "❌ Failed to initialize grafting engine: " & engineResult.error
      return 1

    var engine = engineResult.get()

    # Register adapters based on source
    case cmd.source.toLower():
    of "pacman", "arch":
      let adapter = newPacmanAdapter()
      let registerResult = engine.registerAdapter(adapter)
      if registerResult.isErr:
        echo "❌ Failed to register Pacman adapter: " & registerResult.error
        return 1
    of "nix", "nixpkgs":
      let adapter = newNixAdapter()
      let registerResult = engine.registerAdapter(adapter)
      if registerResult.isErr:
        echo "❌ Failed to register Nix adapter: " & registerResult.error
        return 1
    of "pkgsrc", "netbsd":
      let adapter = newPKGSRCAdapter()
      let registerResult = engine.registerAdapter(adapter)
      if registerResult.isErr:
        echo "❌ Failed to register PKGSRC adapter: " & registerResult.error
        return 1
    else:
      echo "❌ Unknown grafting source: " & cmd.source
      echo "💡 Available sources: pacman, arch, nix, nixpkgs, pkgsrc, netbsd"
      return 1

    # Graft the package
    let graftResult = engine.graftPackage(cmd.source.toLower(), cmd.packageName)
    if graftResult.isErr:
      echo "❌ Grafting failed: " & graftResult.error
      return 1

    let result = graftResult.get()
    if not result.success:
      echo "❌ Grafting failed:"
      for error in result.errors:
        echo "  • " & error
      return 1

    # Success output
    echo "✅ Successfully grafted: " & result.packageId.name & " " & result.packageId.version
    echo "📍 Source: " & result.metadata.source
    echo "🔗 Graft hash: " & result.metadata.graftHash

    # Convert to .npk if requested
    if cmd.convert:
      echo "🔄 Converting to .npk format with build hash integration..."
      let convertResult = engine.convertGraftedPackage(cmd.packageName)
      if convertResult.isErr:
        echo "⚠️  Conversion failed: " & convertResult.error
        return 1
      else:
        echo "✅ Converted to: " & convertResult.get()
        echo "🔗 Build hash calculated and embedded in NPK manifest"

    # Verify if requested
    if cmd.verify:
      echo "🔍 Verifying grafted package..."
      # TODO: Implement verification
      echo "✅ Verification completed"

    # Output in requested format
    if cmd.output != "human":
      outputGraftResult(result, cmd.output)

    return 0

  except Exception as e:
    echo "❌ Unexpected error: " & e.msg
    return 1

proc executeGraftStatusCommand*(cmd: GraftStatusCommand): int =
  ## Execute nip grafting status command
  try:
    let engineResult = initGraftingEngine()
    if engineResult.isErr:
      echo "❌ Failed to initialize grafting engine: " & engineResult.error
      return 1

    let engine = engineResult.get()
    let status = engine.getGraftingStatus()

    if cmd.output == "human":
      echo "🌱 Grafting Engine Status"
      echo "========================"
      echo "Enabled: " & $status["enabled"].getBool()
      echo "Cache Directory: " & status["cache"]["directory"].getStr()
      echo "Cached Packages: " & $status["cache"]["packages"].getInt()
      echo "Active Transactions: " & $status["transactions"].getInt()
      echo ""
      echo "Adapters:"
      for name, info in status["adapters"]:
        let enabled = if info["enabled"].getBool(): "✅" else: "❌"
        echo "  " & enabled & " " & name & " (priority: " & $info["priority"].getInt() & ")"

      if cmd.verbose:
        echo ""
        echo "Grafted Packages:"
        let packages = engine.listGraftedPackages()
        if packages.len == 0:
          echo "  No packages grafted yet"
        else:
          for pkg in packages:
            echo "  📦 " & pkg.packageName & " " & pkg.version & " (from " & pkg.source & ")"
    else:
      echo status.pretty()

    return 0

  except Exception as e:
    echo "❌ Error getting grafting status: " & e.msg
    return 1

proc executeGraftConvertCommand*(cmd: GraftConvertCommand): int =
  ## Execute nip convert <package> command
  echo "🔄 Converting grafted package: " & cmd.packageName

  try:
    let engineResult = initGraftingEngine()
    if engineResult.isErr:
      echo "❌ Failed to initialize grafting engine: " & engineResult.error
      return 1

    var engine = engineResult.get()

    let convertResult = engine.convertGraftedPackage(cmd.packageName)
    if convertResult.isErr:
      echo "❌ Conversion failed: " & convertResult.error
      return 1

    let npkPath = convertResult.get()
    echo "✅ Successfully converted to: " & npkPath
    echo "🔗 NPK includes build hash for reproducibility and NexusBuildToolkit integration"

    if cmd.verify:
      echo "🔍 Verifying converted package..."
      # TODO: Implement NPK verification
      echo "✅ Verification completed"

    if cmd.outputPath != "":
      try:
        copyFile(npkPath, cmd.outputPath)
        echo "📁 Copied to: " & cmd.outputPath
      except IOError as e:
        echo "⚠️  Failed to copy to output path: " & e.msg

    return 0

  except Exception as e:
    echo "❌ Unexpected error: " & e.msg
    return 1

proc outputGraftResult(result: GraftResult, format: string) =
  ## Output graft result in specified format
  let output = %*{
    "success": result.success,
    "package": {
      "name": result.packageId.name,
      "version": result.packageId.version,
      "stream": $result.packageId.stream
    },
    "metadata": {
      "source": result.metadata.source,
      "graftedAt": $result.metadata.graftedAt,
      "graftHash": result.metadata.graftHash,
      "originalHash": result.metadata.originalHash
    },
    "errors": result.errors
  }

  case format.toLower():
  of "json":
    echo output.pretty()
  of "yaml":
    # TODO: Implement YAML output
    echo "# YAML output not yet implemented"
    echo output.pretty()
  of "kdl":
    # TODO: Implement KDL output
    echo "// KDL output not yet implemented"
    echo output.pretty()
  else:
    echo output.pretty()

# Helper functions for CLI argument parsing
proc parseGraftCommand*(args: seq[string]): GraftCommand =
  ## Parse command line arguments for graft command
  var cmd = GraftCommand(
    convert: false,
    verify: false,
    output: "human"
  )

  if args.len < 2:
    raise newException(ValueError, "Usage: nip graft <source> <package> [options]")

  cmd.source = args[0]
  cmd.packageName = args[1]

  # Parse options
  var i = 2
  while i < args.len:
    case args[i]:
    of "--convert":
      cmd.convert = true
    of "--verify":
      cmd.verify = true
    of "--output":
      if i + 1 < args.len:
        cmd.output = args[i + 1]
        i += 1
      else:
        raise newException(ValueError, "--output requires a value")
    else:
      raise newException(ValueError, "Unknown option: " & args[i])
    i += 1

  cmd

proc parseGraftStatusCommand*(args: seq[string]): GraftStatusCommand =
  ## Parse command line arguments for grafting status command
  var cmd = GraftStatusCommand(
    output: "human",
    verbose: false
  )

  var i = 0
  while i < args.len:
    case args[i]:
    of "--output":
      if i + 1 < args.len:
        cmd.output = args[i + 1]
        i += 1
      else:
        raise newException(ValueError, "--output requires a value")
    of "--verbose", "-v":
      cmd.verbose = true
    else:
      raise newException(ValueError, "Unknown option: " & args[i])
    i += 1

  cmd

proc parseGraftConvertCommand*(args: seq[string]): GraftConvertCommand =
  ## Parse command line arguments for convert command
  var cmd = GraftConvertCommand(
    verify: false,
    outputPath: ""
  )

  if args.len < 1:
    raise newException(ValueError, "Usage: nip convert <package> [options]")

  cmd.packageName = args[0]

  var i = 1
  while i < args.len:
    case args[i]:
    of "--verify":
      cmd.verify = true
    of "--output":
      if i + 1 < args.len:
        cmd.outputPath = args[i + 1]
        i += 1
      else:
        raise newException(ValueError, "--output requires a value")
    else:
      raise newException(ValueError, "Unknown option: " & args[i])
    i += 1

  cmd