## NEXTER Container Management Tests
##
## Tests for container lifecycle management including stopping, status checking,
## logs, and restart functionality.

import std/[unittest, os, tempfiles, options, strutils, times, tables]
import nip/container_management
import nip/container_startup
import nip/nexter_manifest
import nip/manifest_parser

# Helper to create a test manifest
proc createTestManifest(name: string, version: string): NEXTERManifest =
  let buildDate = parse("2025-11-28T12:00:00Z", "yyyy-MM-dd'T'HH:mm:ss'Z'")
  return NEXTERManifest(
    name: name,
    version: parseSemanticVersion(version),
    buildDate: buildDate,
    metadata: ContainerInfo(
      description: "Test container",
      license: "MIT"
    ),
    provenance: ProvenanceInfo(
      source: "https://example.com/source.tar.gz",
      sourceHash: "xxh3-source-hash",
      buildTimestamp: buildDate
    ),
    buildConfig: BuildConfiguration(
      configureFlags: @[],
      compilerFlags: @[],
      compilerVersion: "gcc-13",
      targetArchitecture: "x86_64",
      libc: "musl",
      allocator: "jemalloc",
      buildSystem: "custom"
    ),
    base: BaseConfig(
      baseImage: some("alpine"),
      baseVersion: some("3.18")
    ),
    environment: initTable[string, string](),
    casChunks: @[],
    namespace: ContainerNamespace(
      isolationType: "full",
      capabilities: @[],
      mounts: @[],
      devices: @[]
    ),
    startup: StartupConfig(
      command: @["/bin/sh"],
      workingDir: "/",
      user: none(string),
      entrypoint: none(string)
    ),
    buildHash: "xxh3-build-hash",
    signature: SignatureInfo(
      algorithm: "ed25519",
      keyId: "test-key",
      signature: "test-sig"
    )
  )

suite "Container Manager Creation Tests":

  test "Create container manager":
    ## Verify container manager can be created
    
    let manifest = createTestManifest("mgmt-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let manager = createContainerManager("test-container", process, config)
    
    check manager.containerName == "test-container"
    check manager.process.pid == 1234
    check manager.logs.len == 0

  test "Container manager has creation timestamp":
    ## Verify creation timestamp is set
    
    let manifest = createTestManifest("time-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let beforeCreate = now()
    let manager = createContainerManager("test", process, config)
    let afterCreate = now()
    
    check manager.createdAt >= beforeCreate
    check manager.createdAt <= afterCreate

suite "Container Status Tests":

  test "Get container status - running":
    ## Verify status for running container
    
    let manifest = createTestManifest("status-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let manager = createContainerManager("test", process, config)
    let status = getContainerStatus(manager)
    
    # Status will be Stopped since PID 1234 doesn't exist, but that's OK for testing
    check status in [Running, Stopped]

  test "Check if container is running":
    ## Verify running status check
    
    let manifest = createTestManifest("running-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let manager = createContainerManager("test", process, config)
    let isRunning = isContainerRunning(manager)
    
    # Will be false since PID doesn't exist, but that's OK for testing
    check isRunning in [true, false]

  test "Get container stats":
    ## Verify container stats retrieval
    
    let manifest = createTestManifest("stats-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let manager = createContainerManager("test", process, config)
    let stats = getContainerStats(manager)
    
    check stats.name == "test"
    check stats.pid == 1234
    check stats.uptime >= 0

suite "Container Logs Tests":

  test "Add log entry":
    ## Verify log entries can be added
    
    let manifest = createTestManifest("log-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    var manager = createContainerManager("test", process, config)
    manager.addLog(Info, "Test log message")
    
    check manager.logs.len == 1
    check manager.logs[0] == "Test log message"

  test "Get container logs":
    ## Verify logs can be retrieved
    
    let manifest = createTestManifest("getlog-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    var manager = createContainerManager("test", process, config)
    manager.addLog(Info, "Message 1")
    manager.addLog(Warning, "Message 2")
    manager.addLog(Error, "Message 3")
    
    let logs = getContainerLogs(manager)
    
    check logs.len == 3
    check "Message 1" in logs
    check "Message 2" in logs
    check "Message 3" in logs

  test "Get last N logs":
    ## Verify last N logs can be retrieved
    
    let manifest = createTestManifest("lastlog-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    var manager = createContainerManager("test", process, config)
    for i in 1..10:
      manager.addLog(Info, "Message " & $i)
    
    let lastLogs = getLastLogs(manager, 3)
    
    check lastLogs.len == 3
    check "Message 8" in lastLogs
    check "Message 9" in lastLogs
    check "Message 10" in lastLogs

  test "Clear container logs":
    ## Verify logs can be cleared
    
    let manifest = createTestManifest("clear-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    var manager = createContainerManager("test", process, config)
    manager.addLog(Info, "Message 1")
    manager.addLog(Info, "Message 2")
    
    check manager.logs.len == 2
    
    manager.clearContainerLogs()
    
    check manager.logs.len == 0

suite "Container Uptime Tests":

  test "Get container uptime":
    ## Verify uptime calculation
    
    let manifest = createTestManifest("uptime-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let manager = createContainerManager("test", process, config)
    let uptime = getContainerUptime(manager)
    
    check uptime >= 0

  test "Get formatted uptime":
    ## Verify uptime formatting
    
    let manifest = createTestManifest("uptime-fmt-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let manager = createContainerManager("test", process, config)
    let uptimeStr = getContainerUptimeFormatted(manager)
    
    check uptimeStr.len > 0
    check "s" in uptimeStr or "m" in uptimeStr or "h" in uptimeStr or "d" in uptimeStr

suite "Container Formatting Tests":

  test "Format container manager":
    ## Verify manager formatting
    
    let manifest = createTestManifest("fmt-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let manager = createContainerManager("test", process, config)
    let formatted = $manager
    
    check "Container" in formatted
    check "test" in formatted
    check "1234" in formatted

  test "Format container stats":
    ## Verify stats formatting
    
    let manifest = createTestManifest("stats-fmt-test", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let manager = createContainerManager("test", process, config)
    let stats = getContainerStats(manager)
    let formatted = $stats
    
    check "Container Stats" in formatted
    check "test" in formatted
    check "1234" in formatted

suite "Container Management Property Tests":

  test "Property: Manager preserves container name":
    ## Verify container name is preserved
    
    for i in 1..5:
      let name = "container-" & $i
      let manifest = createTestManifest(name, "1.0.0")
      let config = createStartupConfig(manifest)
      let process = ContainerProcess(
        pid: 1000 + i,
        startTime: now(),
        status: Running,
        exitCode: none[int](),
        output: "",
        error: ""
      )
      
      let manager = createContainerManager(name, process, config)
      
      check manager.containerName == name

  test "Property: Logs are accumulated":
    ## Verify logs accumulate correctly
    
    let manifest = createTestManifest("prop-log", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    var manager = createContainerManager("test", process, config)
    
    for i in 1..20:
      manager.addLog(Info, "Log " & $i)
    
    check manager.logs.len == 20
    check getLastLogs(manager, 5).len == 5

  test "Property: Uptime is monotonically increasing":
    ## Verify uptime increases over time
    
    let manifest = createTestManifest("prop-uptime", "1.0.0")
    let config = createStartupConfig(manifest)
    let process = ContainerProcess(
      pid: 1234,
      startTime: now(),
      status: Running,
      exitCode: none[int](),
      output: "",
      error: ""
    )
    
    let manager = createContainerManager("test", process, config)
    let uptime1 = getContainerUptime(manager)
    
    sleep(100)
    
    let uptime2 = getContainerUptime(manager)
    
    check uptime2 >= uptime1
