## Unit Tests for Flexible Adapter
##
## Tests for the flexible adapter implementation which handles
## source-based builds like Gentoo and NPK.

import std/[unittest, options, tables, strutils]
import ../src/nip/resolver/flexible_adapter
import ../src/nip/resolver/source_adapter
import ../src/nip/resolver/variant_types

suite "Flexible Adapter Tests":
  
  test "Create flexible adapter":
    ## Test basic adapter creation
    
    let adapter = newFlexibleAdapter("test-flexible", priority = 30)
    
    check adapter.name == "test-flexible"
    check adapter.class == Flexible
    check adapter.priority == 30
  
  test "Add package to flexible adapter":
    ## Test adding buildable packages
    
    let adapter = newFlexibleAdapter("test-flexible")
    
    var profile = newVariantProfile()
    profile.addFlag("optimization", "lto")
    profile.calculateHash()
    
    let metadata = PackageMetadata(
      name: "nginx",
      version: "1.24.0",
      availableVariants: @[profile],
      sourceHash: "https://nginx.org/download/nginx-1.24.0.tar.gz",
      buildTime: 300  # 5 minutes
    )
    
    adapter.addPackage(metadata)
    
    check adapter.availablePackages.hasKey("nginx")
    check adapter.availablePackages["nginx"].name == "nginx"
    check adapter.availablePackages["nginx"].buildTime == 300
  
  test "canSatisfy: Package available":
    ## Test that available packages are detected
    
    let adapter = newFlexibleAdapter("test-flexible")
    
    var profile = newVariantProfile()
    profile.addFlag("optimization", "lto")
    profile.calculateHash()
    
    let metadata = PackageMetadata(
      name: "nginx",
      version: "1.24.0",
      availableVariants: @[profile],
      sourceHash: "https://nginx.org/download/nginx-1.24.0.tar.gz",
      buildTime: 300
    )
    
    adapter.addPackage(metadata)
    
    let demand = VariantDemand(
      packageName: "nginx",
      variantProfile: profile,
      optional: false
    )
    
    let availability = adapter.canSatisfy(demand)
    
    check availability == Available
  
  test "canSatisfy: Package unavailable":
    ## Test that unavailable packages are detected
    
    let adapter = newFlexibleAdapter("test-flexible")
    
    var profile = newVariantProfile()
    profile.addFlag("optimization", "lto")
    profile.calculateHash()
    
    let demand = VariantDemand(
      packageName: "nonexistent",
      variantProfile: profile,
      optional: false
    )
    
    let availability = adapter.canSatisfy(demand)
    
    check availability == Unavailable
  
  test "canSatisfy: Any variant is acceptable":
    ## Test that flexible sources accept any variant
    ## (they can build with any configuration)
    
    let adapter = newFlexibleAdapter("test-flexible")
    
    var availableProfile = newVariantProfile()
    availableProfile.addFlag("optimization", "lto")
    availableProfile.calculateHash()
    
    let metadata = PackageMetadata(
      name: "nginx",
      version: "1.24.0",
      availableVariants: @[availableProfile],
      sourceHash: "https://nginx.org/download/nginx-1.24.0.tar.gz",
      buildTime: 300
    )
    
    adapter.addPackage(metadata)
    
    # Request different variant
    var demandProfile = newVariantProfile()
    demandProfile.addFlag("optimization", "pgo")
    demandProfile.addFlag("graphics", "wayland")
    demandProfile.calculateHash()
    
    let demand = VariantDemand(
      packageName: "nginx",
      variantProfile: demandProfile,
      optional: false
    )
    
    let availability = adapter.canSatisfy(demand)
    
    # Flexible sources can build any variant
    check availability == Available
  
  test "getVariant: Returns metadata with requested variant":
    ## Test that getVariant returns metadata for any variant
    
    let adapter = newFlexibleAdapter("test-flexible")
    
    var baseProfile = newVariantProfile()
    baseProfile.addFlag("optimization", "lto")
    baseProfile.calculateHash()
    
    let metadata = PackageMetadata(
      name: "nginx",
      version: "1.24.0",
      availableVariants: @[baseProfile],
      sourceHash: "https://nginx.org/download/nginx-1.24.0.tar.gz",
      buildTime: 300
    )
    
    adapter.addPackage(metadata)
    
    # Request different variant
    var demandProfile = newVariantProfile()
    demandProfile.addFlag("optimization", "pgo")
    demandProfile.calculateHash()
    
    let demand = VariantDemand(
      packageName: "nginx",
      variantProfile: demandProfile,
      optional: false
    )
    
    let result = adapter.getVariant(demand)
    
    check result.isSome
    check result.get.name == "nginx"
    check result.get.availableVariants[0] == demandProfile
  
  test "getVariant: Returns none for unavailable package":
    ## Test that getVariant returns none for missing packages
    
    let adapter = newFlexibleAdapter("test-flexible")
    
    var profile = newVariantProfile()
    profile.addFlag("optimization", "lto")
    profile.calculateHash()
    
    let demand = VariantDemand(
      packageName: "nonexistent",
      variantProfile: profile,
      optional: false
    )
    
    let result = adapter.getVariant(demand)
    
    check result.isNone
  
  test "synthesize: Successful build with mock function":
    ## Test successful package synthesis
    
    let mockBuild = mockBuildSuccess("nginx", "cas-nginx-abc123")
    let adapter = newFlexibleAdapter("test-flexible", buildFunc = mockBuild)
    
    var profile = newVariantProfile()
    profile.addFlag("optimization", "lto")
    profile.calculateHash()
    
    let metadata = PackageMetadata(
      name: "nginx",
      version: "1.24.0",
      availableVariants: @[profile],
      sourceHash: "https://nginx.org/download/nginx-1.24.0.tar.gz",
      buildTime: 300
    )
    
    adapter.addPackage(metadata)
    
    let demand = VariantDemand(
      packageName: "nginx",
      variantProfile: profile,
      optional: false
    )
    
    let result = adapter.synthesize(demand)
    
    check result.isOk
    check $result.value == "cas-nginx-abc123"
  
  test "synthesize: Build failure with mock function":
    ## Test build failure handling
    
    let mockBuild = mockBuildFailure("Compilation failed", exitCode = 2)
    let adapter = newFlexibleAdapter("test-flexible", buildFunc = mockBuild)
    
    var profile = newVariantProfile()
    profile.addFlag("optimization", "lto")
    profile.calculateHash()
    
    let metadata = PackageMetadata(
      name: "nginx",
      version: "1.24.0",
      availableVariants: @[profile],
      sourceHash: "https://nginx.org/download/nginx-1.24.0.tar.gz",
      buildTime: 300
    )
    
    adapter.addPackage(metadata)
    
    let demand = VariantDemand(
      packageName: "nginx",
      variantProfile: profile,
      optional: false
    )
    
    let result = adapter.synthesize(demand)
    
    check not result.isOk
    check result.error.exitCode == 2
    check "Compilation failed" in result.error.message
  
  test "synthesize: Package not found":
    ## Test synthesis of non-existent package
    
    let adapter = newFlexibleAdapter("test-flexible")
    
    var profile = newVariantProfile()
    profile.addFlag("optimization", "lto")
    profile.calculateHash()
    
    let demand = VariantDemand(
      packageName: "nonexistent",
      variantProfile: profile,
      optional: false
    )
    
    let result = adapter.synthesize(demand)
    
    check not result.isOk
    check "not found" in result.error.message.toLowerAscii()
  
  test "synthesize: Default implementation generates CAS ID":
    ## Test that default synthesis generates valid CAS ID
    
    let adapter = newFlexibleAdapter("test-flexible")
    
    var profile = newVariantProfile()
    profile.addFlag("optimization", "lto")
    profile.calculateHash()
    
    let metadata = PackageMetadata(
      name: "nginx",
      version: "1.24.0",
      availableVariants: @[profile],
      sourceHash: "https://nginx.org/download/nginx-1.24.0.tar.gz",
      buildTime: 300
    )
    
    adapter.addPackage(metadata)
    
    let demand = VariantDemand(
      packageName: "nginx",
      variantProfile: profile,
      optional: false
    )
    
    let result = adapter.synthesize(demand)
    
    check result.isOk
    # CAS ID should contain package name and variant hash
    let casIdStr = $result.value
    check "nginx" in casIdStr
    check profile.hash in casIdStr
  
  test "synthesize: Variant profile is passed correctly":
    ## Test that the requested variant profile is used in synthesis
    
    var capturedProfile: VariantProfile
    
    let mockBuild = proc(demand: VariantDemand): Result[CasId, BuildError] =
      capturedProfile = demand.variantProfile
      return ok[CasId, BuildError](newCasId("test-cas-id"))
    
    let adapter = newFlexibleAdapter("test-flexible", buildFunc = mockBuild)
    
    var profile = newVariantProfile()
    profile.addFlag("optimization", "lto")
    profile.addFlag("graphics", "wayland")
    profile.calculateHash()
    
    let metadata = PackageMetadata(
      name: "firefox",
      version: "120.0",
      availableVariants: @[profile],
      sourceHash: "https://mozilla.org/firefox-120.0.tar.gz",
      buildTime: 600
    )
    
    adapter.addPackage(metadata)
    
    let demand = VariantDemand(
      packageName: "firefox",
      variantProfile: profile,
      optional: false
    )
    
    let result = adapter.synthesize(demand)
    
    check result.isOk
    check capturedProfile == profile
    check capturedProfile.hasDomain("optimization")
    check capturedProfile.hasDomain("graphics")

