## Test binary cache functionality

import std/[os, times, tables, options]
import ../src/nimpak/build/binary_cache

const TestDir = "/tmp/nip-cache-test"

proc setupTest() =
  if dirExists(TestDir):
    removeDir(TestDir)
  createDir(TestDir)

proc cleanupTest() =
  if dirExists(TestDir):
    removeDir(TestDir)

proc testCacheManager() =
  echo "Testing BinaryCacheManager..."

  let bcm = newBinaryCacheManager(TestDir / "cache")

  if dirExists(bcm.cacheDir):
    echo "✓ Cache directory created"
  else:
    echo "✗ Cache directory not created"
    return

  echo "✓ BinaryCacheManager initialized"

proc testVariantFingerprint() =
  echo "\nTesting variant fingerprint..."

  # Test with USE flags
  let fp1 = calculateVariantFingerprint(
    useFlags = @["python", "ruby"],
    cflags = "-O2"
  )

  # Same flags, different order - should be same fingerprint
  let fp2 = calculateVariantFingerprint(
    useFlags = @["ruby", "python"],
    cflags = "-O2"
  )

  if fp1 == fp2:
    echo "✓ Variant fingerprint is order-independent"
  else:
    echo "✗ Variant fingerprint order-dependent (unexpected)"

  # Different flags - should be different fingerprint
  let fp3 = calculateVariantFingerprint(
    useFlags = @["python"],
    cflags = "-O2"
  )

  if fp1 != fp3:
    echo "✓ Different variants have different fingerprints"
  else:
    echo "✗ Different variants have same fingerprint (unexpected)"

proc testCacheStorage() =
  echo "\nTesting cache storage..."

  let bcm = newBinaryCacheManager(TestDir / "cache")

  # Create a test artifact
  let artifactPath = TestDir / "test-artifact.tar.gz"
  writeFile(artifactPath, "test artifact content")

  # Store in cache
  let fp = calculateVariantFingerprint(useFlags = @["test"])
  let stored = bcm.store(
    "test-package",
    "1.0.0",
    fp,
    artifactPath
  )

  if stored:
    echo "✓ Artifact stored in cache"
  else:
    echo "✗ Failed to store artifact"
    return

  # Verify it's in the index
  let stats = bcm.getStats()
  if stats.totalEntries == 1:
    echo "✓ Cache index updated"
  else:
    echo "✗ Cache index not updated"

proc testCacheLookup() =
  echo "\nTesting cache lookup..."

  let bcm = newBinaryCacheManager(TestDir / "cache")

  # Create and store artifact
  let artifactPath = TestDir / "test-artifact2.tar.gz"
  writeFile(artifactPath, "test artifact content 2")

  let fp = calculateVariantFingerprint(useFlags = @["lookup-test"])
  discard bcm.store("lookup-package", "2.0.0", fp, artifactPath)

  # Look it up
  let entry = bcm.lookup("lookup-package", "2.0.0", fp)

  if entry.isSome:
    echo "✓ Cache lookup successful (hit)"
    let e = entry.get()
    if e.packageName == "lookup-package":
      echo "✓ Correct package retrieved"
  else:
    echo "✗ Cache lookup failed (miss)"
    return

  # Try lookup with wrong fingerprint
  let wrongFp = calculateVariantFingerprint(useFlags = @["wrong"])
  let missEntry = bcm.lookup("lookup-package", "2.0.0", wrongFp)

  if missEntry.isNone:
    echo "✓ Cache miss works correctly"
  else:
    echo "✗ Cache returned entry for wrong fingerprint"

proc testCacheVerification() =
  echo "\nTesting cache verification..."

  let bcm = newBinaryCacheManager(TestDir / "cache")

  # Create and store artifact
  let artifactPath = TestDir / "test-artifact3.tar.gz"
  writeFile(artifactPath, "test artifact content 3")

  let fp = calculateVariantFingerprint(useFlags = @["verify-test"])
  discard bcm.store("verify-package", "3.0.0", fp, artifactPath)

  # Look it up and verify
  let entry = bcm.lookup("verify-package", "3.0.0", fp)

  if entry.isSome:
    if bcm.verify(entry.get()):
      echo "✓ Cache verification successful"
    else:
      echo "✗ Cache verification failed"
  else:
    echo "✗ Could not find entry to verify"

proc testCacheRemoval() =
  echo "\nTesting cache removal..."

  let bcm = newBinaryCacheManager(TestDir / "cache")

  # Create and store artifact
  let artifactPath = TestDir / "test-artifact4.tar.gz"
  writeFile(artifactPath, "test artifact content 4")

  let fp = calculateVariantFingerprint(useFlags = @["remove-test"])
  discard bcm.store("remove-package", "4.0.0", fp, artifactPath)

  # Verify it's there
  let beforeStats = bcm.getStats()
  let entriesBefore = beforeStats.totalEntries

  # Remove it
  let removed = bcm.remove("remove-package", "4.0.0", fp)

  if removed:
    echo "✓ Cache entry removed"

    # Verify it's gone
    let afterStats = bcm.getStats()
    if afterStats.totalEntries == entriesBefore - 1:
      echo "✓ Cache index updated after removal"
    else:
      echo "✗ Cache index not updated correctly"
  else:
    echo "✗ Failed to remove cache entry"

proc testCacheStats() =
  echo "\nTesting cache statistics..."

  let bcm = newBinaryCacheManager(TestDir / "cache")

  # Add some entries
  for i in 1..3:
    let artifactPath = TestDir / "artifact" & $i & ".tar.gz"
    writeFile(artifactPath, "content " & $i)
    let fp = calculateVariantFingerprint(useFlags = @["test" & $i])
    discard bcm.store("pkg" & $i, "1.0.0", fp, artifactPath)

  # Do some lookups
  let fp1 = calculateVariantFingerprint(useFlags = @["test1"])
  discard bcm.lookup("pkg1", "1.0.0", fp1)  # Hit
  discard bcm.lookup("pkg-nonexistent", "1.0.0", fp1)  # Miss

  let stats = bcm.getStats()

  echo "  Entries: ", stats.totalEntries
  echo "  Hits: ", stats.hits
  echo "  Misses: ", stats.misses

  if stats.totalEntries == 3:
    echo "✓ Correct number of entries"
  else:
    echo "✗ Incorrect number of entries"

proc main() =
  echo "Binary Cache Tests"
  echo "==================\n"

  setupTest()

  testCacheManager()
  testVariantFingerprint()
  testCacheStorage()
  testCacheLookup()
  testCacheVerification()
  testCacheRemoval()
  testCacheStats()

  cleanupTest()

  echo "\n✅ All tests complete!"

when isMainModule:
  main()
