# core/nip/src/nimpak/cli/store_commands.nim
## CLI Commands for Nexus CAS (Content Addressable Storage)

import std/[options, strutils, strformat, terminal, os]
import ../types
import ../errors
import ../cas
import ../logger

proc storeHelpCommand() =
  echo """
NIP STORE - Sovereign CAS Interface

USAGE:
  nip store <command> [arguments]

COMMANDS:
  push <file>            Store a file in CAS (returns hash)
  fetch <hash> <dest>    Retrieve file from CAS by hash
  verify <hash>          Check if object exists and verify integrity
  gc                     Run garbage collection on CAS
  stats                  Show CAS statistics
  path <hash>            Show physical path of object (if exists)

EXAMPLES:
  nip store push mybinary.elf
  nip store fetch xxh3-123... /tmp/restored.elf
  nip store verify xxh3-123...
  nip store stats
"""

proc storePushCommand*(args: seq[string], verbose: bool): int =
  ## Push a file to CAS
  if args.len < 1:
    errorLog("Usage: nip store push <file>")
    return 1

  let filePath = args[0]
  if not fileExists(filePath):
    errorLog(fmt"File not found: {filePath}")
    return 1

  let cas = initCasManager()
  
  if verbose: showInfo(fmt"Storing '{filePath}'...")
  
  let res = cas.storeFile(filePath)
  if res.isOk:
    let obj = res.get()
    if verbose:
      showInfo(fmt"Stored successfully.")
      showInfo(fmt"  Original Size:   {obj.size} bytes")
      showInfo(fmt"  Compressed Size: {obj.compressedSize} bytes")
      showInfo(fmt"  Chunks:          {obj.chunks.len}")
    
    # Output ONLY the hash to stdout for piping support
    echo obj.hash
    return 0
  else:
    errorLog(formatError(res.getError()))
    return 1

proc storeFetchCommand*(args: seq[string], verbose: bool): int =
  ## Fetch a file from CAS
  if args.len < 2:
    errorLog("Usage: nip store fetch <hash> <destination>")
    return 1

  let hash = args[0]
  let destPath = args[1]
  
  # Remove prefix if user typed "fetch cas:<hash>" or similar
  let cleanHash = if hash.contains(":"): hash.split(":")[1] else: hash

  let cas = initCasManager()
  
  if verbose: showInfo(fmt"Fetching object {cleanHash} to {destPath}...")

  let res = cas.retrieveFile(cleanHash, destPath)
  if res.isOk:
    if verbose: showInfo("Success.")
    return 0
  else:
    errorLog(formatError(res.getError()))
    return 1

proc storeVerifyCommand*(args: seq[string], verbose: bool): int =
  ## Verify object existence and integrity
  if args.len < 1:
    errorLog("Usage: nip store verify <hash>")
    return 1

  let hash = args[0]
  let cas = initCasManager()

  if cas.objectExists(hash):
    # Retrieve to verify integrity (checksum check happens during retrieve logic implicitly if we extended it, 
    # currently retrieveObject just reads. Ideally we should re-hash.)
    
    # Simple existence check for MVP
    showInfo(fmt"Object {hash} exists.")
    
    # Check if we can read it
    let res = cas.retrieveObject(hash)
    if res.isOk:
      let data = res.get()
      let computed = cas.computeHash(data)
      if computed == hash:
        showInfo("Integrity: VERIFIED (" & $data.len & " bytes)")
        return 0
      else:
        errorLog(fmt"Integrity: FAILED (Computed: {computed})")
        return 1
    else:
      errorLog("Corruption: Object exists in index/path but cannot be read.")
      return 1
  else:
    errorLog(fmt"Object {hash} NOT FOUND.")
    return 1

proc storeStatsCommand*(verbose: bool): int =
  let cas = initCasManager()
  # MVP stats
  # Since we don't have a persistent counter file in this MVP definition other than 'cas_index.kdl' which we parse manually?
  # CasManager has 'CasStats' type but no automatic loadStats() method exposed in cas.nim yet.
  # We will just show directory sizes.
  
  showInfo("CAS Storage Statistics")
  showInfo(fmt"Root: {cas.rootPath}")
  
  # Simple walkdir to count
  var count = 0
  var size = 0'i64
  
  for kind, path in walkDir(cas.rootPath / "objects", relative=true):
    # Recurse... for MVP just simple ls of shards
    discard
    
  showInfo("(Detailed stats pending implementation)")
  return 0

proc storePathCommand*(args: seq[string], verbose: bool): int =
  if args.len < 1: 
    return 1
  let hash = args[0]
  let cas = initCasManager()
  let path = getObjectPath(cas.rootPath, hash)
  if fileExists(path):
    echo path
    return 0
  else:
    return 1

proc dispatchStoreCommand*(args: seq[string], verbose: bool): int =
  if args.len == 0:
    storeHelpCommand()
    return 0

  let cmd = args[0].toLowerAscii()
  let subArgs = if args.len > 1: args[1..^1] else: @[]

  case cmd
  of "push": return storePushCommand(subArgs, verbose)
  of "fetch", "pull": return storeFetchCommand(subArgs, verbose)
  of "verify": return storeVerifyCommand(subArgs, verbose)
  of "stats": return storeStatsCommand(verbose)
  of "path": return storePathCommand(subArgs, verbose)
  of "help": 
    storeHelpCommand()
    return 0
  else:
    errorLog(fmt"Unknown store command: {cmd}")
    storeHelpCommand()
    return 1
