import std/[unittest, os, tempfiles, strutils, options, asyncdispatch, json, times]
import ../src/nimpak/repo/publish
import ../src/nimpak/types_fixed
import ../src/nimpak/cas

suite "Publish Pipeline Tests":
  
  setup:
    let tempDir = createTempDir("nip_test_publish_", "")
    let casRoot = tempDir / "cas"
    let keysRoot = tempDir / "keys"
    let outputDir = tempDir / "output"
    let sourceDir = tempDir / "source"
    
    createDir(casRoot)
    createDir(keysRoot)
    createDir(outputDir)
    createDir(sourceDir)
    
    # Create some source files
    writeFile(sourceDir / "hello.txt", "Hello Nexus!")
    createDir(sourceDir / "subdir")
    writeFile(sourceDir / "subdir" / "config.conf", "enabled=true")
    
    var builder = newArtifactBuilder(casRoot, keysRoot, outputDir)
    builder.config.signPackage = false

  teardown:
    removeDir(tempDir)

  test "Build package from directory":
    let result = builder.buildFromDirectory(sourceDir, "test-pkg", "1.0.0")
    
    check result.isOk
    if result.isOk:
      let npk = types_fixed.get(result)
      check npk.metadata.id.name == "test-pkg"
      check npk.metadata.id.version == "1.0.0"
      check npk.files.len == 2
      
      # Verify files are in CAS
      for file in npk.files:
        check builder.cas.objectExists(file.hash)

  test "Create package archive":
    # First build
    let buildResult = builder.buildFromDirectory(sourceDir, "test-pkg", "1.0.0")
    require buildResult.isOk
    let npk = types_fixed.get(buildResult)
    
    # Then archive
    let archiveResult = builder.createArchive(npk)
    check archiveResult.isOk
    
    if archiveResult.isOk:
      let archivePath = types_fixed.get(archiveResult)
      check fileExists(archivePath)
      check archivePath.endsWith(".npk.zst")

  test "Build package from CAS":
    # 1. Build from directory to populate CAS
    let dirResult = builder.buildFromDirectory(sourceDir, "cas-pkg-source", "1.0.0")
    require dirResult.isOk
    let sourceNpk = types_fixed.get(dirResult)
    
    # 2. Create source from CAS (using files from first build)
    let casSource = ArtifactSource(
      kind: FromCas,
      files: sourceNpk.files
    )
    
    # 3. Publish from CAS source
    let pubResult = waitFor builder.publish(casSource, "cas-pkg-dest", "2.0.0")
    
    check pubResult.success
    check pubResult.packageName == "cas-pkg-dest"
    check pubResult.version == "2.0.0"
    check pubResult.casHash.len > 0
    
    # Verify the new package is in CAS
    check builder.cas.objectExists(pubResult.casHash)

  test "Build package from Graft result":
    # 1. Simulate a graft result
    let graftRes = types_fixed.GraftResult(
      fragment: Fragment(
         id: PackageId(name: "grafted-pkg", version: "3.0.0", stream: types_fixed.Stable)
      ),
      extractedPath: sourceDir,
      originalMetadata: newJNull(),
      auditLog: GraftAuditLog(
         timestamp: now(),
         source: types_fixed.Pacman,
         packageName: "grafted-pkg",
         version: "3.0.0",
         downloadedFilename: "test.pkg",
         archiveHash: "test-hash",
         hashAlgorithm: "blake2b",
         sourceOutput: "",
         originalSize: 100,
         deduplicationStatus: "New",
         blake2bHash: "test-hash",
         downloadUrl: none(string)
      )
    )
    
    # 2. Create source
    let graftSource = ArtifactSource(
      kind: FromGraft,
      graftResult: graftRes
    )
    
    # 3. Publish
    let pubResult = waitFor builder.publish(graftSource, "grafted-final", "3.0.0")
    
    check pubResult.success
    check pubResult.packageName == "grafted-final"
    check pubResult.version == "3.0.0"
    check builder.cas.objectExists(pubResult.casHash)
