## cache_commands.nim
## CLI commands for binary cache management

import std/[strutils, times, tables]
import ../build/[binary_cache, remote_cache]

proc cacheInfoCommand*(): int =
  ## Show cache information
  let bcm = newBinaryCacheManager()

  echo bcm.getCacheInfo()
  return 0

proc cacheListCommand*(): int =
  ## List cached artifacts
  let bcm = newBinaryCacheManager()

  let entries = bcm.listEntries()

  if entries.len == 0:
    echo "No cached artifacts"
    return 0

  echo "Cached Artifacts:"
  echo "================="
  echo ""

  for entry in entries:
    let age = getTime() - entry.buildTime
    let ageStr = if age.inDays > 0:
      $age.inDays & " days ago"
    elif age.inHours > 0:
      $age.inHours & " hours ago"
    else:
      $age.inMinutes & " minutes ago"

    echo "  ", entry.packageName, "-", entry.version
    echo "    Variant: ", entry.variantFingerprint
    echo "    Size: ", formatSize(entry.size)
    echo "    Cached: ", ageStr
    echo ""

  echo "Total: ", entries.len, " artifacts (", formatSize(bcm.getStats().totalSize), ")"
  return 0

proc cacheStatsCommand*(): int =
  ## Show cache statistics
  let bcm = newBinaryCacheManager()
  let stats = bcm.getStats()

  echo "Cache Statistics:"
  echo "================="
  echo ""
  echo "Entries: ", stats.totalEntries
  echo "Total Size: ", formatSize(stats.totalSize)
  echo ""
  echo "Hits: ", stats.hits
  echo "Misses: ", stats.misses

  if stats.hits + stats.misses > 0:
    echo "Hit Rate: ", $(stats.hitRate * 100).formatFloat(ffDecimal, 1), "%"

  return 0

proc cacheCleanCommand*(): int =
  ## Clean old cache entries
  let bcm = newBinaryCacheManager()

  echo "Cleaning old cache entries..."
  let removed = bcm.cleanOldEntries()

  if removed > 0:
    echo "✅ Removed ", removed, " old entries"
  else:
    echo "✅ No old entries to remove"

  return 0

proc cachePruneCommand*(): int =
  ## Enforce cache size limit
  let bcm = newBinaryCacheManager()

  echo "Enforcing cache size limit..."
  let removed = bcm.enforceSizeLimit()

  if removed > 0:
    echo "✅ Removed ", removed, " entries to stay under size limit"
  else:
    echo "✅ Cache is within size limit"

  return 0

proc cacheClearCommand*(): int =
  ## Clear entire cache
  echo "⚠️  This will remove all cached artifacts"
  stdout.write("Continue? (y/N): ")
  stdout.flushFile()

  let response = stdin.readLine().strip().toLower()

  if response != "y" and response != "yes":
    echo "Cancelled"
    return 0

  let bcm = newBinaryCacheManager()
  let removed = bcm.clear()

  echo "✅ Cleared cache (", removed, " entries removed)"
  return 0

proc cacheRemoveCommand*(packageName, version: string): int =
  ## Remove specific package from cache
  let bcm = newBinaryCacheManager()

  # Find entries matching package and version
  var found = false
  for entry in bcm.listEntries():
    if entry.packageName == packageName and entry.version == version:
      if bcm.remove(entry.packageName, entry.version, entry.variantFingerprint):
        echo "✅ Removed: ", entry.packageName, "-", entry.version, " (", entry.variantFingerprint, ")"
        found = true

  if not found:
    echo "❌ No cached artifacts found for ", packageName, "-", version
    return 1

  return 0

proc cacheVerifyCommand*(): int =
  ## Verify cache integrity
  let bcm = newBinaryCacheManager()

  echo "Verifying cache integrity..."

  var verified = 0
  var failed = 0

  for entry in bcm.listEntries():
    if bcm.verify(entry):
      verified.inc
    else:
      echo "❌ Verification failed: ", entry.packageName, "-", entry.version
      failed.inc

  echo ""
  echo "Verified: ", verified
  echo "Failed: ", failed

  if failed > 0:
    echo ""
    echo "Run 'nip cache clean' to remove invalid entries"
    return 1

  echo "✅ All cache entries verified"
  return 0

proc remoteConfigCommand*(url, apiKey: string = "", enable: bool = false, disable: bool = false): int =
  ## Configure remote cache
  var config = loadConfig()

  if url.len > 0:
    config.url = url
    echo "✅ Remote cache URL set to: ", url

  if apiKey.len > 0:
    config.apiKey = apiKey
    echo "✅ API key configured"

  if enable:
    config.enabled = true
    echo "✅ Remote cache enabled"

  if disable:
    config.enabled = false
    echo "✅ Remote cache disabled"

  saveConfig(config)
  return 0

proc remoteStatusCommand*(): int =
  ## Show remote cache status
  let config = loadConfig()

  echo "Remote Cache Status"
  echo "==================="
  echo ""
  echo "Enabled: ", if config.enabled: "Yes" else: "No"
  echo "URL: ", if config.url.len > 0: config.url else: "(not configured)"
  echo "API Key: ", if config.apiKey.len > 0: "***configured***" else: "(not configured)"
  echo "Timeout: ", config.timeout, " seconds"
  echo ""

  if config.enabled and config.url.len > 0:
    echo "Testing connection..."
    let bcm = newBinaryCacheManager()
    let client = newRemoteCacheClient(config, bcm)

    if client.checkAvailability():
      echo "✅ Remote cache is available"
    else:
      echo "❌ Remote cache is not available"
      return 1

  return 0

proc remotePullCommand*(packageName, version: string): int =
  ## Pull artifact from remote cache
  let config = loadConfig()

  if not config.enabled:
    echo "❌ Remote cache is not enabled"
    echo "Run: nip cache remote config --enable"
    return 1

  let bcm = newBinaryCacheManager()
  let client = newRemoteCacheClient(config, bcm)

  if not client.checkAvailability():
    echo "❌ Remote cache is not available"
    return 1

  echo "🌐 Pulling from remote cache..."

  # For now, we need variant fingerprint - in real usage this would come from build config
  # This is a simplified version for manual pulls
  let variantFp = calculateVariantFingerprint()

  let success = client.download(packageName, version, variantFp)

  if success:
    echo "✅ Successfully pulled from remote cache"
    return 0
  else:
    echo "❌ Failed to pull from remote cache"
    return 1

proc remotePushCommand*(packageName, version: string): int =
  ## Push artifact to remote cache
  let config = loadConfig()

  if not config.enabled:
    echo "❌ Remote cache is not enabled"
    echo "Run: nip cache remote config --enable"
    return 1

  let bcm = newBinaryCacheManager()

  # Find local cache entry
  let variantFp = calculateVariantFingerprint()
  let entry = bcm.lookup(packageName, version, variantFp)

  if entry.isNone:
    echo "❌ Package not found in local cache"
    echo "Build the package first: nip build ", packageName
    return 1

  let client = newRemoteCacheClient(config, bcm)

  if not client.checkAvailability():
    echo "❌ Remote cache is not available"
    return 1

  echo "🌐 Pushing to remote cache..."

  let success = client.upload(
    packageName,
    version,
    variantFp,
    entry.get().artifactPath
  )

  if success:
    echo "✅ Successfully pushed to remote cache"
    return 0
  else:
    echo "❌ Failed to push to remote cache"
    return 1

proc cacheHelpCommand*(): int =
  ## Show cache command help
  echo """
NIP Binary Cache Commands
==========================

The binary cache speeds up builds by storing compiled artifacts.

Local Cache Commands:
  nip cache info              Show cache information
  nip cache list              List cached artifacts
  nip cache stats             Show cache statistics
  nip cache clean             Remove old entries
  nip cache prune             Enforce size limit
  nip cache clear             Clear entire cache
  nip cache remove <pkg> <ver> Remove specific package
  nip cache verify            Verify cache integrity

Remote Cache Commands:
  nip cache remote config     Configure remote cache
    --url <url>               Set remote cache URL
    --api-key <key>           Set API key
    --enable                  Enable remote cache
    --disable                 Disable remote cache
  nip cache remote status     Show remote cache status
  nip cache remote pull <pkg> <ver>  Pull from remote cache
  nip cache remote push <pkg> <ver>  Push to remote cache

Examples:
  # Local cache
  nip cache info
  nip cache list
  nip cache clean

  # Configure remote cache
  nip cache remote config --url https://cache.example.com --enable
  nip cache remote config --api-key your-api-key-here

  # Check remote cache status
  nip cache remote status

  # Manual push/pull (usually automatic during builds)
  nip cache remote push vim 9.0
  nip cache remote pull vim 9.0

Configuration:
  Local cache: ~/.cache/nip/binary-cache/
  Remote config: ~/.config/nip/remote-cache.json
  Max size: 10GB (configurable)
  Max age: 30 days (configurable)

Remote Cache Benefits:
  • Share builds across team members
  • Speed up CI/CD pipelines
  • Reduce build server load
  • Automatic upload/download during builds

For more information:
  https://git.maiwald.work/Nexus/NexusToolKit/wiki/Binary-Cache
"""
  return 0
