## NIP Archive Handler
##
## This module handles the creation and extraction of .nip (and .npk) archives.
## It enforces the compression strategy:
## - Archives: zstd (default/auto) for performance.
## - CAS: zstd -19 (handled by cas.nim, not here).

import std/[os, osproc, strutils, strformat, logging, tempfiles]
import nip/manifest_parser

type
  ArchiveError* = object of CatchableError

proc runCmd(cmd: string) =
  let res = execCmdEx(cmd)
  if res.exitCode != 0:
    raise newException(ArchiveError, fmt"Command failed: {cmd}{'\n'}Output: {res.output}")

proc createArchive*(manifest: PackageManifest, sourceDir: string, outputFile: string) =
  ## Create a .nip archive from a source directory and manifest.
  ## The archive will contain:
  ## - manifest.kdl
  ## - files/ (content of sourceDir)
  
  info(fmt"Creating archive {outputFile} from {sourceDir}")
  
  let tempDir = createTempDir("nip_build_", "")
  defer: removeDir(tempDir)
  
  # 1. Write manifest to temp root
  let manifestPath = tempDir / "manifest.kdl"
  writeFile(manifestPath, serializeManifestToKDL(manifest))
  
  # 2. Copy source files to temp/files
  let filesDir = tempDir / "files"
  createDir(filesDir)
  copyDirWithPermissions(sourceDir, filesDir)
  
  # 3. Create Archive
  # We use tar + zstd.
  # --zstd tells tar to use zstd. If not supported by tar version, we pipe.
  # To be safe and explicit about zstd options, we pipe.
  # cd tempDir && tar -cf - manifest.kdl files/ | zstd -T0 > outputFile
  # -T0 uses all cores.
  # No -19 here, just default (level 3 usually) or --auto if we wanted.
  # Default is good for "superb heuristic".
  
  let cmd = fmt"tar -C {tempDir.quoteShell} -cf - manifest.kdl files | zstd -T0 -o {outputFile.quoteShell}"
  runCmd(cmd)
  
  info(fmt"Archive created successfully: {outputFile}")

proc extractArchive*(archivePath: string, targetDir: string) =
  ## Extract a .nip archive to targetDir.
  
  info(fmt"Extracting archive {archivePath} to {targetDir}")
  createDir(targetDir)
  
  # zstd -d -c archive | tar -C target -xf -
  let cmd = fmt"zstd -d -c {archivePath.quoteShell} | tar -C {targetDir.quoteShell} -xf -"
  runCmd(cmd)
  
  info("Extraction complete")

proc verifyArchive*(archivePath: string): bool =
  ## Verify archive integrity (zstd check)
  let cmd = fmt"zstd -t {archivePath.quoteShell}"
  let res = execCmdEx(cmd)
  return res.exitCode == 0
