## test_variant_paths.nim
## Tests for variant path management
## Ensures proper path generation, validation, and parsing

import std/[unittest, strutils]
import ../src/nimpak/variant_paths
import ../src/nimpak/variant_types

suite "Path Generation Tests":

  test "Generate basic variant path":
    let path = generateVariantPath("nginx", "1.28.0", "blake2b-abc123def456")
    check path == "/Programs/nginx/1.28.0-blake2b-abc123def456"

  test "Generate path with different package":
    let path = generateVariantPath("firefox", "120.0", "blake2b-xyz789")
    check path == "/Programs/firefox/120.0-blake2b-xyz789"

  test "Generate path with complex version":
    let path = generateVariantPath("python", "3.11.5-rc1", "blake2b-aaa111")
    check path == "/Programs/python/3.11.5-rc1-blake2b-aaa111"

  test "Empty package name raises error":
    expect(ValueError):
      discard generateVariantPath("", "1.0.0", "blake2b-abc123")

  test "Empty version raises error":
    expect(ValueError):
      discard generateVariantPath("nginx", "", "blake2b-abc123")

  test "Empty fingerprint raises error":
    expect(ValueError):
      discard generateVariantPath("nginx", "1.0.0", "")

suite "Path Validation Tests":

  test "Valid variant path passes validation":
    check validateVariantPath("/Programs/nginx/1.28.0-blake2b-abc123def456") == true

  test "Valid path with trailing slash":
    check validateVariantPath("/Programs/nginx/1.28.0-blake2b-abc123def456/") == true

  test "Invalid path without Programs":
    check validateVariantPath("/usr/local/nginx/1.28.0-blake2b-abc123") == false

  test "Invalid path without fingerprint":
    check validateVariantPath("/Programs/nginx/1.28.0") == false

  test "Invalid path with wrong fingerprint format":
    check validateVariantPath("/Programs/nginx/1.28.0-abc123") == false

  test "Empty path is invalid":
    check validateVariantPath("") == false

  test "Path with too few components is invalid":
    check validateVariantPath("/Programs/nginx") == false

  test "isValidVariantPath alias works":
    check isValidVariantPath("/Programs/nginx/1.28.0-blake2b-abc123") == true

suite "Path Parsing Tests":

  test "Extract package name from path":
    let name = extractPackageNameFromPath("/Programs/nginx/1.28.0-blake2b-abc123/")
    check name == "nginx"

  test "Extract version from path":
    let version = extractVersionFromPath("/Programs/nginx/1.28.0-blake2b-abc123/")
    check version == "1.28.0"

  test "Extract fingerprint from path":
    let fp = extractFingerprintFromPath("/Programs/nginx/1.28.0-blake2b-abc123def456/")
    check fp == "blake2b-abc123def456"

  test "Extract from complex version":
    let version = extractVersionFromPath("/Programs/python/3.11.5-rc1-blake2b-xyz789/")
    check version == "3.11.5-rc1"

  test "Extract from path without trailing slash":
    let name = extractPackageNameFromPath("/Programs/firefox/120.0-blake2b-aaa111")
    check name == "firefox"

  test "Extract from invalid path raises error":
    expect(ValueError):
      discard extractPackageNameFromPath("/invalid/path")

suite "Path Query Tests":

  test "Get variant base path":
    let basePath = getVariantBasePath("nginx")
    check basePath == "/Programs/nginx"

  test "Get variant bin path":
    let binPath = getVariantBinPath("/Programs/nginx/1.28.0-blake2b-abc123/")
    check binPath == "/Programs/nginx/1.28.0-blake2b-abc123/bin"

  test "Get variant lib path":
    let libPath = getVariantLibPath("/Programs/nginx/1.28.0-blake2b-abc123/")
    check libPath == "/Programs/nginx/1.28.0-blake2b-abc123/lib"

  test "Get variant include path":
    let incPath = getVariantIncludePath("/Programs/nginx/1.28.0-blake2b-abc123/")
    check incPath == "/Programs/nginx/1.28.0-blake2b-abc123/include"

  test "Get variant share path":
    let sharePath = getVariantSharePath("/Programs/nginx/1.28.0-blake2b-abc123/")
    check sharePath == "/Programs/nginx/1.28.0-blake2b-abc123/share"


suite "Path Comparison Tests":

  test "Same variant paths are equal":
    let path1 = "/Programs/nginx/1.28.0-blake2b-abc123/"
    let path2 = "/Programs/nginx/1.28.0-blake2b-abc123/"
    check isSameVariant(path1, path2) == true

  test "Different fingerprints are not equal":
    let path1 = "/Programs/nginx/1.28.0-blake2b-abc123/"
    let path2 = "/Programs/nginx/1.28.0-blake2b-def456/"
    check isSameVariant(path1, path2) == false

  test "Compare variant paths by version":
    let path1 = "/Programs/nginx/1.27.0-blake2b-abc123/"
    let path2 = "/Programs/nginx/1.28.0-blake2b-abc123/"
    check compareVariantPaths(path1, path2) < 0

  test "Compare variant paths by fingerprint":
    let path1 = "/Programs/nginx/1.28.0-blake2b-aaa111/"
    let path2 = "/Programs/nginx/1.28.0-blake2b-bbb222/"
    check compareVariantPaths(path1, path2) < 0

  test "Compare identical paths":
    let path = "/Programs/nginx/1.28.0-blake2b-abc123/"
    check compareVariantPaths(path, path) == 0

suite "Path Utilities Tests":

  test "Normalize path adds trailing slash":
    let normalized = normalizeVariantPath("/Programs/nginx/1.28.0-blake2b-abc123")
    check normalized.endsWith("/")

  test "Normalize path adds leading slash":
    let normalized = normalizeVariantPath("Programs/nginx/1.28.0-blake2b-abc123")
    check normalized.startsWith("/")

  test "Normalize already normalized path":
    let path = "/Programs/nginx/1.28.0-blake2b-abc123/"
    let normalized = normalizeVariantPath(path)
    check normalized == path

suite "VariantPathInfo Tests":

  test "Parse valid variant path":
    let info = parseVariantPath("/Programs/nginx/1.28.0-blake2b-abc123def456/")
    check info.isValid == true
    check info.packageName == "nginx"
    check info.version == "1.28.0"
    check info.fingerprint == "blake2b-abc123def456"

  test "Parse invalid variant path":
    let info = parseVariantPath("/invalid/path")
    check info.isValid == false

  test "String representation of valid path info":
    let info = parseVariantPath("/Programs/nginx/1.28.0-blake2b-abc123/")
    let str = $info
    check "nginx" in str
    check "1.28.0" in str

  test "String representation of invalid path info":
    let info = parseVariantPath("/invalid/path")
    let str = $info
    check "invalid" in str

suite "Path Conflict Detection Tests":

  test "No conflicts in different packages":
    let paths = @[
      "/Programs/nginx/1.28.0-blake2b-abc123/",
      "/Programs/firefox/120.0-blake2b-def456/"
    ]
    let conflicts = detectPathConflicts(paths)
    check conflicts.len == 0

  test "No conflicts in different versions":
    let paths = @[
      "/Programs/nginx/1.27.0-blake2b-abc123/",
      "/Programs/nginx/1.28.0-blake2b-abc123/"
    ]
    let conflicts = detectPathConflicts(paths)
    check conflicts.len == 0

  test "Detect conflict in same package/version with different fingerprints":
    let paths = @[
      "/Programs/nginx/1.28.0-blake2b-abc123/",
      "/Programs/nginx/1.28.0-blake2b-def456/"
    ]
    let conflicts = detectPathConflicts(paths)
    check conflicts.len == 1

  test "No conflicts with same fingerprint":
    let paths = @[
      "/Programs/nginx/1.28.0-blake2b-abc123/",
      "/Programs/nginx/1.28.0-blake2b-abc123/"
    ]
    let conflicts = detectPathConflicts(paths)
    check conflicts.len == 0

suite "Edge Cases Tests":

  test "Package name with hyphens":
    let path = generateVariantPath("my-package", "1.0.0", "blake2b-abc123")
    check path == "/Programs/my-package/1.0.0-blake2b-abc123"

    let name = extractPackageNameFromPath(path)
    check name == "my-package"

  test "Version with multiple hyphens":
    let path = generateVariantPath("pkg", "1.0.0-rc1-beta2", "blake2b-abc123")
    let version = extractVersionFromPath(path)
    check version == "1.0.0-rc1-beta2"

  test "Long fingerprint":
    let longFp = "blake2b-" & "a".repeat(60)
    let path = generateVariantPath("nginx", "1.0.0", longFp)
    let extracted = extractFingerprintFromPath(path)
    check extracted == longFp

  test "Package name with numbers":
    let path = generateVariantPath("python3", "3.11.5", "blake2b-abc123")
    check path == "/Programs/python3/3.11.5-blake2b-abc123"

  test "Version with dots and numbers":
    let path = generateVariantPath("pkg", "2.0.1.5", "blake2b-xyz789")
    let version = extractVersionFromPath(path)
    check version == "2.0.1.5"

suite "Real-World Path Tests":

  test "Nginx variant path":
    let path = generateVariantPath("nginx", "1.28.0", "blake2b-89ab4c5d")
    check validateVariantPath(path) == true
    check extractPackageNameFromPath(path) == "nginx"
    check extractVersionFromPath(path) == "1.28.0"

  test "Firefox variant path":
    let path = generateVariantPath("firefox", "120.0", "blake2b-def67890")
    check validateVariantPath(path) == true
    check extractPackageNameFromPath(path) == "firefox"

  test "Python variant path":
    let path = generateVariantPath("python", "3.11.5", "blake2b-abc12345")
    check validateVariantPath(path) == true
    check extractVersionFromPath(path) == "3.11.5"

  test "Complex package with all features":
    let path = generateVariantPath("my-app", "2.1.0-rc1", "blake2b-fedcba98")

    check validateVariantPath(path) == true

    let info = parseVariantPath(path)
    check info.isValid == true
    check info.packageName == "my-app"
    check info.version == "2.1.0-rc1"
    check info.fingerprint == "blake2b-fedcba98"

    check getVariantBinPath(path) == "/Programs/my-app/2.1.0-rc1-blake2b-fedcba98/bin"

when isMainModule:
  echo "Running variant paths tests..."


suite "Hash Algorithm Compatibility Tests":

  test "Validate blake2b path":
    check validateVariantPath("/Programs/nginx/1.28.0-blake2b-abc123/") == true

  test "Validate blake3 path (future compatibility)":
    check validateVariantPath("/Programs/nginx/1.28.0-blake3-xyz789/") == true

  test "Detect blake2b algorithm":
    let algo = detectHashAlgorithm("/Programs/nginx/1.28.0-blake2b-abc123/")
    check algo == "blake2b"

  test "Detect blake3 algorithm":
    let algo = detectHashAlgorithm("/Programs/nginx/1.28.0-blake3-xyz789/")
    check algo == "blake3"

  test "Extract version from blake3 path":
    let version = extractVersionFromPath("/Programs/nginx/1.28.0-blake3-xyz789/")
    check version == "1.28.0"

  test "Extract fingerprint from blake3 path":
    let fp = extractFingerprintFromPath("/Programs/nginx/1.28.0-blake3-xyz789abc/")
    check fp == "blake3-xyz789abc"

  test "Parse blake3 variant path":
    let info = parseVariantPath("/Programs/firefox/120.0-blake3-fedcba98/")
    check info.isValid == true
    check info.packageName == "firefox"
    check info.version == "120.0"
    check info.fingerprint == "blake3-fedcba98"

  test "Blake2b and blake3 variants can coexist":
    let paths = @[
      "/Programs/nginx/1.28.0-blake2b-abc123/",
      "/Programs/nginx/1.28.0-blake3-xyz789/"
    ]
    # These are different fingerprints (different algorithms), detected as different variants
    # The conflict detector will flag them as same version but different fingerprints
    # This is actually correct - they ARE different variants that can coexist
    let conflicts = detectPathConflicts(paths)
    check conflicts.len == 1  # Detected as "conflict" but both are valid

  test "Compare blake2b and blake3 paths":
    let path1 = "/Programs/nginx/1.28.0-blake2b-abc123/"
    let path2 = "/Programs/nginx/1.28.0-blake3-xyz789/"
    # Different fingerprints
    check isSameVariant(path1, path2) == false

  test "Invalid hash algorithm rejected":
    check validateVariantPath("/Programs/nginx/1.28.0-md5-abc123/") == false
    check validateVariantPath("/Programs/nginx/1.28.0-sha256-abc123/") == false

suite "Migration Scenario Tests":

  test "Old blake2b packages remain valid after blake3 introduction":
    # Simulate existing blake2b packages
    let oldPath = "/Programs/nginx/1.27.0-blake2b-old123/"
    check validateVariantPath(oldPath) == true
    check detectHashAlgorithm(oldPath) == "blake2b"

    # New blake3 packages also valid
    let newPath = "/Programs/nginx/1.28.0-blake3-new456/"
    check validateVariantPath(newPath) == true
    check detectHashAlgorithm(newPath) == "blake3"

  test "Mixed hash algorithms in variant listing":
    # Both old and new packages can be listed
    let paths = @[
      "/Programs/nginx/1.27.0-blake2b-abc123/",
      "/Programs/nginx/1.28.0-blake3-def456/",
      "/Programs/nginx/1.29.0-blake3-ghi789/"
    ]

    for path in paths:
      check validateVariantPath(path) == true

  test "Path operations work regardless of hash algorithm":
    let blake2Path = "/Programs/nginx/1.0.0-blake2b-aaa111/"
    let blake3Path = "/Programs/nginx/2.0.0-blake3-bbb222/"

    # All operations should work on both
    check extractPackageNameFromPath(blake2Path) == "nginx"
    check extractPackageNameFromPath(blake3Path) == "nginx"

    check getVariantBinPath(blake2Path) == "/Programs/nginx/1.0.0-blake2b-aaa111/bin"
    check getVariantBinPath(blake3Path) == "/Programs/nginx/2.0.0-blake3-bbb222/bin"
