## tests/test_nippels_cli.nim
## Comprehensive tests for Nippels CLI commands

import std/[unittest, os, strformat, options, tables]
import ../src/nimpak/[nippels, nippels_cli, nippel_types, profile_manager]

# Test setup
const testRoot = "/tmp/nippels_cli_test"

proc setupTest(): NippelManager =
  if dirExists(testRoot):
    removeDir(testRoot)
  createDir(testRoot)
  result = newNippelManager(testRoot)

proc teardownTest() =
  if dirExists(testRoot):
    removeDir(testRoot)

suite "Nippels CLI Commands":

  setup:
    var manager {.used.} = setupTest()

  teardown:
    teardownTest()

  # ==========================================================================
  # Test: nip cell create
  # ==========================================================================

  test "cmdCellCreate - basic creation":
    let opts = CreateOptions(
      name: "test-cell",
      profile: SecurityProfile.Homestation,
      isolation: IsolationLevel.Standard,
      overrides: ProfileOverrides(),
      description: "Test cell"
    )

    let exitCode = cmdCellCreate(manager, opts)
    check exitCode == 0

    let nippel = manager.getNippel("test-cell")
    check nippel.isSome
    check nippel.get.name == "test-cell"
    check nippel.get.profile == SecurityProfile.Homestation

  test "cmdCellCreate - with custom profile":
    let opts = CreateOptions(
      name: "workstation-cell",
      profile: SecurityProfile.Workstation,
      isolation: IsolationLevel.Strict,
      overrides: ProfileOverrides(),
      description: "Workstation test"
    )

    let exitCode = cmdCellCreate(manager, opts)
    check exitCode == 0

    let nippel = manager.getNippel("workstation-cell")
    check nippel.isSome
    check nippel.get.profile == SecurityProfile.Workstation
    check nippel.get.isolationLevel == IsolationLevel.Strict

  test "cmdCellCreate - with profile overrides":
    var overrides = ProfileOverrides()
    overrides.isolationLevel = some(IsolationLevel.None)
    overrides.networkAccess = some(NetworkAccessLevel.NoNetwork)

    let opts = CreateOptions(
      name: "custom-cell",
      profile: SecurityProfile.Homestation,
      isolation: IsolationLevel.Standard,
      overrides: overrides,
      description: "Custom overrides"
    )

    let exitCode = cmdCellCreate(manager, opts)
    check exitCode == 0

    let nippel = manager.getNippel("custom-cell")
    check nippel.isSome
    check nippel.get.isolationLevel == IsolationLevel.None
    check nippel.get.profileSettings.networkAccess == NetworkAccessLevel.NoNetwork

  test "cmdCellCreate - duplicate name fails":
    let opts1 = CreateOptions(
      name: "duplicate",
      profile: SecurityProfile.Homestation,
      isolation: IsolationLevel.Standard,
      overrides: ProfileOverrides(),
      description: "First"
    )

    check cmdCellCreate(manager, opts1) == 0

    let opts2 = CreateOptions(
      name: "duplicate",
      profile: SecurityProfile.Homestation,
      isolation: IsolationLevel.Standard,
      overrides: ProfileOverrides(),
      description: "Second"
    )

    check cmdCellCreate(manager, opts2) != 0

  # ==========================================================================
  # Test: nip cell list
  # ==========================================================================

  test "cmdCellList - empty list":
    let exitCode = cmdCellList(manager, verbose = false)
    check exitCode == 0

  test "cmdCellList - with cells":
    # Create some cells
    discard manager.createNippel("cell1", SecurityProfile.Homestation, ProfileOverrides())
    discard manager.createNippel("cell2", SecurityProfile.Workstation, ProfileOverrides())
    discard manager.createNippel("cell3", SecurityProfile.Server, ProfileOverrides())

    let exitCode = cmdCellList(manager, verbose = false)
    check exitCode == 0

    let nippels = manager.listNippels()
    check nippels.len == 3

  test "cmdCellList - verbose mode":
    discard manager.createNippel("verbose-cell", SecurityProfile.Homestation, ProfileOverrides())

    let exitCode = cmdCellList(manager, verbose = true)
    check exitCode == 0

  test "cmdCellList - shows active status":
    discard manager.createNippel("active-cell", SecurityProfile.Homestation, ProfileOverrides())
    discard manager.activateNippel("active-cell")

    let exitCode = cmdCellList(manager, verbose = false)
    check exitCode == 0
    check manager.isNippelActive("active-cell")

  # ==========================================================================
  # Test: nip cell activate/deactivate
  # ==========================================================================

  test "cmdCellActivate - successful activation":
    discard manager.createNippel("activate-test", SecurityProfile.Homestation, ProfileOverrides())

    let exitCode = cmdCellActivate(manager, "activate-test")
    check exitCode == 0
    check manager.isNippelActive("activate-test")

  test "cmdCellActivate - nonexistent cell fails":
    let exitCode = cmdCellActivate(manager, "nonexistent")
    check exitCode != 0

  test "cmdCellDeactivate - successful deactivation":
    discard manager.createNippel("deactivate-test", SecurityProfile.Homestation, ProfileOverrides())
    discard manager.activateNippel("deactivate-test")

    check manager.isNippelActive("deactivate-test")

    let exitCode = cmdCellDeactivate(manager, "deactivate-test")
    check exitCode == 0
    check not manager.isNippelActive("deactivate-test")

  test "cmdCellDeactivate - nonexistent cell fails":
    let exitCode = cmdCellDeactivate(manager, "nonexistent")
    check exitCode != 0

  test "cmdCellDeactivate - inactive cell fails":
    discard manager.createNippel("inactive-test", SecurityProfile.Homestation, ProfileOverrides())

    let exitCode = cmdCellDeactivate(manager, "inactive-test")
    check exitCode != 0

  # ==========================================================================
  # Test: nip cell profile list
  # ==========================================================================

  test "cmdCellProfileList - shows all profiles":
    let exitCode = cmdCellProfileList()
    check exitCode == 0

  # ==========================================================================
  # Test: nip cell profile show
  # ==========================================================================

  test "cmdCellProfileShow - shows profile settings":
    discard manager.createNippel("profile-show-test", SecurityProfile.Workstation, ProfileOverrides())

    let exitCode = cmdCellProfileShow(manager, "profile-show-test")
    check exitCode == 0

  test "cmdCellProfileShow - nonexistent cell fails":
    let exitCode = cmdCellProfileShow(manager, "nonexistent")
    check exitCode != 0

  # ==========================================================================
  # Test: nip cell profile set
  # ==========================================================================

  test "cmdCellProfileSet - changes profile":
    discard manager.createNippel("profile-set-test", SecurityProfile.Homestation, ProfileOverrides())

    let exitCode = cmdCellProfileSet(manager, "profile-set-test", SecurityProfile.Server)
    check exitCode == 0

    let nippel = manager.getNippel("profile-set-test")
    check nippel.isSome
    check nippel.get.profile == SecurityProfile.Server

  test "cmdCellProfileSet - nonexistent cell fails":
    let exitCode = cmdCellProfileSet(manager, "nonexistent", SecurityProfile.Server)
    check exitCode != 0

  # ==========================================================================
  # Test: nip cell verify
  # ==========================================================================

  test "cmdCellVerify - verifies merkle tree":
    discard manager.createNippel("verify-test", SecurityProfile.Homestation, ProfileOverrides())

    let exitCode = cmdCellVerify(manager, "verify-test")
    check exitCode == 0

  test "cmdCellVerify - nonexistent cell fails":
    let exitCode = cmdCellVerify(manager, "nonexistent")
    check exitCode != 0

  test "cmdCellVerify - no merkle tree warning":
    discard manager.createNippel("no-merkle-test", SecurityProfile.Homestation, ProfileOverrides())
    # Remove merkle tree
    del(manager.merkleTrees, "no-merkle-test")

    let exitCode = cmdCellVerify(manager, "no-merkle-test")
    check exitCode == 2  # Warning code

  # ==========================================================================
  # Test: nip cell query
  # ==========================================================================

  test "cmdCellQuery - queries nippel state":
    discard manager.createNippel("query-test", SecurityProfile.Homestation, ProfileOverrides())

    let nippel = manager.getNippel("query-test").get
    let address = formatUTCPAddress(nippel.utcpAddress)

    let exitCode = cmdCellQuery(manager, address)
    check exitCode == 0

  test "cmdCellQuery - queries merkle tree":
    discard manager.createNippel("query-merkle-test", SecurityProfile.Homestation, ProfileOverrides())

    let nippel = manager.getNippel("query-merkle-test").get
    let address = formatUTCPAddress(nippel.utcpAddress) & "/merkle"

    let exitCode = cmdCellQuery(manager, address)
    check exitCode == 0

  test "cmdCellQuery - queries profile":
    discard manager.createNippel("query-profile-test", SecurityProfile.Workstation, ProfileOverrides())

    let nippel = manager.getNippel("query-profile-test").get
    let address = formatUTCPAddress(nippel.utcpAddress) & "/profile"

    let exitCode = cmdCellQuery(manager, address)
    check exitCode == 0

  test "cmdCellQuery - invalid address fails":
    let exitCode = cmdCellQuery(manager, "invalid-address")
    check exitCode != 0

  test "cmdCellQuery - nonexistent nippel fails":
    let exitCode = cmdCellQuery(manager, "utcp://localhost/nippel/nonexistent")
    check exitCode != 0

  # ==========================================================================
  # Test: nip cell info
  # ==========================================================================

  test "cmdCellInfo - shows detailed information":
    discard manager.createNippel("info-test", SecurityProfile.Workstation, ProfileOverrides())

    let exitCode = cmdCellInfo(manager, "info-test")
    check exitCode == 0

  test "cmdCellInfo - nonexistent cell fails":
    let exitCode = cmdCellInfo(manager, "nonexistent")
    check exitCode != 0

  test "cmdCellInfo - shows active status":
    discard manager.createNippel("info-active-test", SecurityProfile.Homestation, ProfileOverrides())
    discard manager.activateNippel("info-active-test")

    let exitCode = cmdCellInfo(manager, "info-active-test")
    check exitCode == 0
    check manager.isNippelActive("info-active-test")

  # ==========================================================================
  # Test: nip cell delete
  # ==========================================================================

  test "cmdCellDelete - deletes inactive cell":
    discard manager.createNippel("delete-test", SecurityProfile.Homestation, ProfileOverrides())

    let exitCode = cmdCellDelete(manager, "delete-test", force = false)
    check exitCode == 0

    let nippel = manager.getNippel("delete-test")
    check nippel.isNone

  test "cmdCellDelete - fails on active cell without force":
    discard manager.createNippel("delete-active-test", SecurityProfile.Homestation, ProfileOverrides())
    discard manager.activateNippel("delete-active-test")

    let exitCode = cmdCellDelete(manager, "delete-active-test", force = false)
    check exitCode != 0

    # Cell should still exist
    let nippel = manager.getNippel("delete-active-test")
    check nippel.isSome

  test "cmdCellDelete - force deletes active cell":
    discard manager.createNippel("delete-force-test", SecurityProfile.Homestation, ProfileOverrides())
    discard manager.activateNippel("delete-force-test")

    let exitCode = cmdCellDelete(manager, "delete-force-test", force = true)
    check exitCode == 0

    let nippel = manager.getNippel("delete-force-test")
    check nippel.isNone

  test "cmdCellDelete - nonexistent cell fails":
    let exitCode = cmdCellDelete(manager, "nonexistent", force = false)
    check exitCode != 0

  # ==========================================================================
  # Test: Integration scenarios
  # ==========================================================================

  test "Full workflow - create, activate, verify, deactivate, delete":
    # Create
    let createOpts = CreateOptions(
      name: "workflow-test",
      profile: SecurityProfile.Workstation,
      isolation: IsolationLevel.Strict,
      overrides: ProfileOverrides(),
      description: "Full workflow test"
    )
    check cmdCellCreate(manager, createOpts) == 0

    # Activate
    check cmdCellActivate(manager, "workflow-test") == 0
    check manager.isNippelActive("workflow-test")

    # Verify
    check cmdCellVerify(manager, "workflow-test") == 0

    # Query
    let nippel = manager.getNippel("workflow-test").get
    let address = formatUTCPAddress(nippel.utcpAddress)
    check cmdCellQuery(manager, address) == 0

    # Info
    check cmdCellInfo(manager, "workflow-test") == 0

    # Deactivate
    check cmdCellDeactivate(manager, "workflow-test") == 0
    check not manager.isNippelActive("workflow-test")

    # Delete
    check cmdCellDelete(manager, "workflow-test", force = false) == 0
    check manager.getNippel("workflow-test").isNone

  test "Multiple cells workflow":
    # Create multiple cells with different profiles
    let profiles = [
      ("home", SecurityProfile.Homestation),
      ("work", SecurityProfile.Workstation),
      ("server", SecurityProfile.Server)
    ]

    for (name, profile) in profiles:
      let opts = CreateOptions(
        name: name,
        profile: profile,
        isolation: IsolationLevel.Standard,
        overrides: ProfileOverrides(),
        description: fmt"Test {name}"
      )
      check cmdCellCreate(manager, opts) == 0

    # List all
    check cmdCellList(manager, verbose = false) == 0
    check manager.listNippels().len == 3

    # Activate one
    check cmdCellActivate(manager, "work") == 0

    # Verify all
    for (name, _) in profiles:
      check cmdCellVerify(manager, name) == 0

    # Change profile
    check cmdCellProfileSet(manager, "home", SecurityProfile.Satellite) == 0

    # Deactivate
    check cmdCellDeactivate(manager, "work") == 0

    # Delete all
    for (name, _) in profiles:
      check cmdCellDelete(manager, name, force = false) == 0

    check manager.listNippels().len == 0

echo "✓ All Nippels CLI tests completed"
