# tests/test_install.nim
# Unit tests for installation orchestrator

import unittest, tables
import ../src/nimpak/[install, dependency, types, errors, transactions, filesystem, cas]

suite "Installation Orchestrator Tests":

  setup:
    # Create test fragments
    let pkgA = PackageId(name: "pkgA", version: "1.0", stream: Stable)
    let pkgB = PackageId(name: "pkgB", version: "1.0", stream: Stable)

    let fragmentA = Fragment(
      id: pkgA,
      dependencies: @[pkgB],
      source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http),
      buildSystem: CMake,
      metadata: PackageMetadata(description: "Test package A"),
      acul: AculCompliance(required: false)
    )

    let fragmentB = Fragment(
      id: pkgB,
      dependencies: @[],
      source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http),
      buildSystem: CMake,
      metadata: PackageMetadata(description: "Test package B"),
      acul: AculCompliance(required: false)
    )

    var fragments = initTable[PackageId, Fragment]()
    fragments[pkgA] = fragmentA
    fragments[pkgB] = fragmentB

    let fsManager = FilesystemManager(
      programsRoot: "/tmp/test/Programs",
      indexRoot: "/tmp/test/Index"
    )

    let casManager = CasManager(
      userCasPath: "/tmp/test/.nip/cas",
      systemCasPath: "/tmp/test/var/lib/nip/cas",
      compression: true,
      compressionLevel: 3
    )

  test "Create installation plan":
    let planResult = createInstallPlan(@[pkgA], fragments)
    check planResult.isOk

    let plan = planResult.get()
    check plan.steps.len == 2  # pkgA and pkgB

    # Check step ordering (dependencies first)
    check plan.steps[0].package.name == "pkgB"
    check plan.steps[1].package.name == "pkgA"

    # Check step numbering
    check plan.steps[0].stepNumber == 1
    check plan.steps[1].stepNumber == 2
    check plan.steps[0].totalSteps == 2
    check plan.steps[1].totalSteps == 2

  test "Installation plan validation":
    let planResult = createInstallPlan(@[pkgA], fragments)
    check planResult.isOk

    let plan = planResult.get()
    let validationResult = validateInstallPlan(plan)
    check validationResult.isOk

  test "Empty installation plan validation":
    let emptyPlan = InstallPlan(
      steps: @[],
      transaction: Transaction(),
      rollbackData: @[]
    )

    let validationResult = validateInstallPlan(emptyPlan)
    check validationResult.isErr
    check validationResult.error.code == InvalidOperation

  test "Installation progress tracking":
    let planResult = createInstallPlan(@[pkgA], fragments)
    check planResult.isOk

    let plan = planResult.get()

    # Test progress at different steps
    let progress1 = getInstallProgress(plan, 1)
    check progress1.currentStep == 1
    check progress1.totalSteps == 2
    check progress1.currentPackage.name == "pkgB"
    check progress1.status == Installing

    let progress2 = getInstallProgress(plan, 2)
    check progress2.currentStep == 2
    check progress2.totalSteps == 2
    check progress2.currentPackage.name == "pkgA"
    check progress2.status == Completed

  test "Progress formatting":
    let progress = InstallProgress(
      currentStep: 1,
      totalSteps: 3,
      currentPackage: pkgA,
      status: Installing
    )

    let formatted = formatInstallProgress(progress)
    check "33%" in formatted
    check "pkgA" in formatted
    check "(1/3)" in formatted

  test "Installation summary generation":
    let planResult = createInstallPlan(@[pkgA], fragments)
    check planResult.isOk

    let plan = planResult.get()
    let summary = getInstallSummary(plan)

    check "Installation Plan Summary" in summary
    check "Total packages: 2" in summary
    check "pkgA" in summary
    check "pkgB" in summary

  test "Multiple package installation plan":
    let pkgC = PackageId(name: "pkgC", version: "1.0", stream: Stable)
    let fragmentC = Fragment(
      id: pkgC,
      dependencies: @[],
      source: Source(url: "test", hash: "test", hashAlgorithm: "blake2b", method: Http),
      buildSystem: CMake,
      metadata: PackageMetadata(description: "Test package C"),
      acul: AculCompliance(required: false)
    )

    var testFragments = fragments
    testFragments[pkgC] = fragmentC

    let planResult = createInstallPlan(@[pkgA, pkgC], testFragments)
    check planResult.isOk

    let plan = planResult.get()
    check plan.steps.len == 3  # pkgA, pkgB, pkgC

    # Check that dependencies are handled correctly
    let packageNames = plan.steps.mapIt(it.package.name)
    check "pkgA" in packageNames
    check "pkgB" in packageNames
    check "pkgC" in packageNames

  test "Installation plan with missing dependencies":
    let pkgMissing = PackageId(name: "missing", version: "1.0", stream: Stable)

    let planResult = createInstallPlan(@[pkgMissing], fragments)
    check planResult.isErr
    check planResult.error.code == PackageNotFound