## nimpak/security/integrity_monitor.nim
## Integrity monitoring and health checks for NimPak
##
## This module implements:
## - nip verify <package|--all> command
## - nip doctor --integrity health-check plugin
## - Real-time filesystem watcher for tamper detection
## - Integration with runHealthChecks() framework

import std/[os, times, json, tables, sequtils, strutils, strformat, asyncdispatch, algorithm, options]
import hash_verifier, signature_verifier_working, keyring_manager, event_logger
import ../cli/core

type
  IntegrityCheckType* = enum
    CheckFileIntegrity = "file_integrity"
    CheckSignatureValidity = "signature_validity"
    CheckKeyringHealth = "keyring_health"
    CheckCRLFreshness = "crl_freshness"
    CheckPackageConsistency = "package_consistency"
    CheckSystemGeneration = "system_generation"

  IntegrityCheckResult* = object
    checkType*: IntegrityCheckType
    packageName*: string
    success*: bool
    message*: string
    details*: JsonNode
    checkTime*: times.DateTime
    duration*: float

  IntegrityViolation* = object
    violationType*: string
    packageName*: string
    filePath*: string
    expectedHash*: string
    actualHash*: string
    detectedAt*: times.DateTime
    severity*: SecuritySeverity

  IntegrityMonitor* = object
    monitoringEnabled*: bool
    watchedPaths*: seq[string]
    lastFullScan*: times.DateTime
    violationCount*: int64
    config*: IntegrityConfig

  IntegrityConfig* = object
    enableRealtimeWatcher*: bool
    scanInterval*: int           # Seconds between full scans
    watchPaths*: seq[string]     # Paths to monitor
    alertThreshold*: int         # Violations before alert
    autoRepair*: bool           # Attempt automatic repair
    quarantineCorrupted*: bool  # Move corrupted files to quarantine

# =============================================================================
# Integrity Monitor Initialization
# =============================================================================

proc newIntegrityMonitor*(config: IntegrityConfig): IntegrityMonitor =
  ## Create a new integrity monitor
  IntegrityMonitor(
    monitoringEnabled: true,
    watchedPaths: config.watchPaths,
    lastFullScan: default(times.DateTime),
    violationCount: 0,
    config: config
  )

proc getDefaultIntegrityConfig*(): IntegrityConfig =
  ## Get default integrity monitoring configuration
  IntegrityConfig(
    enableRealtimeWatcher: true,
    scanInterval: 3600,          # 1 hour
    watchPaths: @[
      "/Programs",               # All installed packages
      "/System/Index",           # Symlinks
      "/System/Generations",     # Generation metadata
      "/etc/nexus/keyrings"      # System keyrings
    ],
    alertThreshold: 5,
    autoRepair: false,           # Conservative default
    quarantineCorrupted: true
  )

# =============================================================================
# Package Verification Commands
# =============================================================================

proc verifyPackageIntegrity*(packageName: string, packagePath: string): IntegrityCheckResult =
  ## Verify integrity of a single package
  let startTime = cpuTime()

  var result = IntegrityCheckResult(
    checkType: CheckFileIntegrity,
    packageName: packageName,
    success: false,
    message: "",
    details: newJObject(),
    checkTime: now().utc(),
    duration: 0.0
  )

  try:
    if not fileExists(packagePath):
      result.message = fmt"Package file not found: {packagePath}"
      return result

    # Check if package has expected hash metadata
    let manifestPath = packagePath.replace(".npk", ".manifest.json")
    if not fileExists(manifestPath):
      result.message = "Package manifest not found"
      return result

    # Load expected hash from manifest
    let manifestContent = readFile(manifestPath)
    let manifest = parseJson(manifestContent)

    if not manifest.hasKey("package_hash"):
      result.message = "Package hash not found in manifest"
      return result

    let expectedHash = manifest["package_hash"].getStr()

    # Verify package hash
    let hashResult = verifyFileHash(packagePath, expectedHash)

    if hashResult.verified:
      result.success = true
      result.message = fmt"Package integrity verified: {packageName}"
      result.details = %*{
        "package_path": packagePath,
        "hash_algorithm": $hashResult.algorithm,
        "hash_verified": true,
        "verification_time": hashResult.computeTime
      }
    else:
      result.message = fmt"Package integrity check failed: {packageName}"
      result.details = %*{
        "package_path": packagePath,
        "expected_hash": expectedHash,
        "verification_failed": true
      }

  except Exception as e:
    result.message = fmt"Integrity chr: {e.msg}"
    result.details = %*{"error": e.msg}

  finally:
    result.duration = cpuTime() - startTime

  return result

proc verifyPackageSignature*(packageName: string, packagePath: string,
                            keyringManager: KeyringManager): IntegrityCheckResult =
  ## Verify signature of a single package
  let startTime = cpuTime()

  var result = IntegrityCheckResult(
    checkType: CheckSignatureValidity,
    packageName: packageName,
    success: false,
    message: "",
    details: newJObject(),
    checkTime: now().utc(),
    duration: 0.0
  )

  try:
    let signaturePath = packagePath & ".sig"
    if not fileExists(signaturePath):
      result.message = "Package signature file not found"
      return result

    # Load signature
    let signatureContent = readFile(signaturePath)
    let signatureJson = parseJson(signatureContent)

    let signature = createDigitalSignature(
      parseEnum[SignatureAlgorithm](signatureJson["algorithm"].getStr()),
      signatureJson["key_id"].getStr(),
      signatureJson["signature"].getStr(),
      signatureJson["timestamp"].getStr().parse("yyyy-MM-dd'T'HH:mm:ss'.'fff'Z'", utc())
    )

    # Find trusted key
    let keyOpt = keyringManager.findKey(signature.keyId)
    if keyOpt.isNone():
      result.message = fmt"Trusted key not found: {signature.keyId}"
      return result

    let key = keyOpt.get()

    # Check if key is revoked
    if keyringManager.isKeyRevoked(signature.keyId):
      result.message = fmt"Package signed with revoked key: {signature.keyId}"
      result.details = %*{
        "key_id": signature.keyId,
        "key_revoked": true,
        "revoked_at": if key.revokedAt.isSome(): $key.revokedAt.get() else: "unknown"
      }
      return result

    # Verify signature (placeholder - would use actual verification)
    let verified = verifyEd25519FileSignature(packagePath, signature.signature, key.publicKey.keyData)

    if verified:
      result.success = true
      result.message = fmt"Package signature verified: {packageName}"
      result.details = %*{
        "key_id": signature.keyId,
        "algorithm": $signature.algorithm,
        "signature_verified": true,
        "key_status": $key.status
      }
    else:
      result.message = fmt"Package signature verification failed: {packageName}"
      result.details = %*{
        "key_id": signature.keyId,
        "signature_verified": false
      }

  except Exception as e:
    result.message = fmt"Signature verification error: {e.msg}"
    result.details = %*{"error": e.msg}

  finally:
    result.duration = cpuTime() - startTime

  return result

proc verifyAllPackages*(monitor: IntegrityMonitor): seq[IntegrityCheckResult] =
  ## Verify integrity of all installed packages
  var results: seq[IntegrityCheckResult] = @[]

  # Initialize keyring manager
  let config = getDefaultKeyringConfig()
  var keyringManager = newKeyringManager(config)
  keyringManager.loadAllKeyrings()

  # Scan /Programs directory for packages
  if dirExists("/Programs"):
    for packageDir in walkDirs("/Programs/*"):
      let packageName = extractFilename(packageDir)

      # Look for package files
      for versionDir in walkDirs(packageDir / "*"):
        let packageFile = versionDir / (packageName & ".npk")
        if fileExists(packageFile):
          # Verify file integrity
          let integrityResult = verifyPackageIntegrity(packageName, packageFile)
          results.add(integrityResult)

          # Verify signature if present
          let signatureResult = verifyPackageSignature(packageName, packageFile, keyringManager)
          results.add(signatureResult)

  return results

# =============================================================================
# Health Check Integration
# =============================================================================

proc runIntegrityHealthCheck*(monitor: IntegrityMonitor): IntegrityCheckResult =
  ## Run comprehensive integrity health check
  let startTime = cpuTime()

  var result = IntegrityCheckResult(
    checkType: CheckPackageConsistency,
    packageName: "system",
    success: true,
    message: "",
    details: newJObject(),
    checkTime: now().utc(),
    duration: 0.0
  )

  var issues: seq[string] = @[]
  var stats = %*{
    "packages_checked": 0,
    "integrity_passed": 0,
    "integrity_failed": 0,
    "signatures_verified": 0,
    "signatures_failed": 0,
    "revoked_keys_found": 0
  }

  try:
    # Run verification on all packages
    let verificationResults = verifyAllPackages(monitor)

    for checkResult in verificationResults:
      stats["packages_checked"] = newJInt(stats["packages_checked"].getInt() + 1)

      case checkResult.checkType:
      of CheckFileIntegrity:
        if checkResult.success:
          stats["integrity_passed"] = newJInt(stats["integrity_passed"].getInt() + 1)
        else:
          stats["integrity_failed"] = newJInt(stats["integrity_failed"].getInt() + 1)
          issues.add(fmt"Integrity: {checkResult.packageName} - {checkResult.message}")

      of CheckSignatureValidity:
        if checkResult.success:
          stats["signatures_verified"] = newJInt(stats["signatures_verified"].getInt() + 1)
        else:
          stats["signatures_failed"] = newJInt(stats["signatures_failed"].getInt() + 1)
          issues.add(fmt"Signature: {checkResult.packageName} - {checkResult.message}")

          # Check for revoked keys
          if checkResult.details.hasKey("key_revoked") and checkResult.details["key_revoked"].getBool():
            stats["revoked_keys_found"] = newJInt(stats["revoked_keys_found"].getInt() + 1)

      else:
        discard

    # Determine overall health
    let totalIssues = issues.len
    if totalIssues == 0:
      result.message = "System integrity check passed - no issues found"
    elif totalIssues <= monitor.config.alertThreshold:
      result.message = fmt"System integrity check completed with {totalIssues} minor issues"
    else:
      result.success = false
      result.message = fmt"System integrity check failed with {totalIssues} issues"

    result.details = %*{
      "statistics": stats,
      "issues": issues,
      "total_issues": totalIssues,
      "alert_threshold": monitor.config.alertThreshold
    }

  except Exception as e:
    result.success = false
    result.message = fmt"Health check error: {e.msg}"
    result.details = %*{"error": e.msg}

  finally:
    result.duration = cpuTime() - startTime

  return result

# =============================================================================
# Real-time Filesystem Monitoring
# =============================================================================

type
  FileWatchEvent* = object
    path*: string
    eventType*: string  # "modified", "created", "deleted"
    timestamp*: times.DateTime
    expectedHash*: Option[string]

  PeriodicScanConfig* = object
    enabled*: bool
    intervalSeconds*: int
    fullScanHour*: int  # Hour of day for full system scan (0-23)
    incrementalScanMinutes*: int  # Minutes between incremental scans

proc getDefaultPeriodicScanConfig*(): PeriodicScanConfig =
  ## Get default periodic scan configuration
  PeriodicScanConfig(
    enabled: true,
    intervalSeconds: 3600,  # 1 hour
    fullScanHour: 2,        # 2 AM for full scan
    incrementalScanMinutes: 15  # Every 15 minutes for incremental
  )

# Forward declarations
proc processFileWatchEvent*(monitor: IntegrityMonitor, event: FileWatchEvent) {.async.}
proc extractPackageName*(filePath: string): string
proc quarantineCorruptedFile*(filePath: string, violation: IntegrityViolation): bool
proc findRecentlyModifiedPackages*(monitor: IntegrityMonitor, minutesBack: int): seq[string]

proc startFilesystemWatcher*(monitor: var IntegrityMonitor) {.async.} =
  ## Start real-time filesystem monitoring with enhanced capabilities
  if not monitor.config.enableRealtimeWatcher:
    return

  logGlobalSecurityEvent(EventSystemStartup, SeverityInfo, "integrity-monitor",
    "Starting real-time filesystem watcher")

  # Track file modification times for change detection
  var lastModTimes: Table[string, times.Time]

  # Initialize baseline modification times
  for watchPath in monitor.watchedPaths:
    if dirExists(watchPath):
      for file in walkDirRec(watchPath):
        try:
          lastModTimes[file] = getLastModificationTime(file)
        except:
          discard

  while monitor.monitoringEnabled:
    try:
      var eventsDetected: seq[FileWatchEvent] = @[]

      # Check watched paths for modifications
      for watchPath in monitor.watchedPaths:
        if dirExists(watchPath):
          for file in walkDirRec(watchPath):
            try:
              let currentModTime = getLastModificationTime(file)

              if file in lastModTimes:
                if currentModTime != lastModTimes[file]:
                  # File was modified
                  eventsDetected.add(FileWatchEvent(
                    path: file,
                    eventType: "modified",
                    timestamp: now(),
                    expectedHash: none(string)
                  ))
                  lastModTimes[file] = currentModTime
              else:
                # New file created
                eventsDetected.add(FileWatchEvent(
                  path: file,
                  eventType: "created",
                  timestamp: now(),
                  expectedHash: none(string)
                ))
                lastModTimes[file] = currentModTime

            except Exception as e:
              debugLog(fmt"Error checking file {file}: {e.msg}")

      # Check for deleted files
      var filesToRemove: seq[string] = @[]
      for trackedFile in lastModTimes.keys:
        if not fileExists(trackedFile):
          eventsDetected.add(FileWatchEvent(
            path: trackedFile,
            eventType: "deleted",
            timestamp: now(),
            expectedHash: none(string)
          ))
          filesToRemove.add(trackedFile)

      # Remove deleted files from tracking
      for file in filesToRemove:
        lastModTimes.del(file)

      # Process detected events
      for event in eventsDetected:
        await processFileWatchEvent(monitor, event)

      # Sleep for a short interval
      await sleepAsync(5000)  # 5 seconds

    except Exception as e:
      logGlobalSecurityEvent(EventSecurityIncident, SeverityError, "integrity-monitor",
        fmt"Filesystem watcher error: {e.msg}")
      await sleepAsync(10000)  # Wait longer on error

proc processFileWatchEvent*(monitor: IntegrityMonitor, event: FileWatchEvent) {.async.} =
  ## Process a filesystem watch event
  try:
    case event.eventType:
    of "modified":
      # Check if this is a package file that should be immutable
      if event.path.contains("/Programs/") and event.path.endsWith(".npk"):
        let packageName = extractPackageName(event.path)

        # This is a critical integrity violation
        let violation = IntegrityViolation(
          violationType: "package_modified",
          packageName: packageName,
          filePath: event.path,
          expectedHash: "",  # Would need to look up from manifest
          actualHash: "",    # Would need to compute
          detectedAt: event.timestamp,
          severity: SeverityCritical
        )

        # Log the violation
        logGlobalSecurityEvent(EventSecurityIncident, SeverityCritical, "integrity-monitor",
          fmt"CRITICAL: Package file modified: {event.path}")

        # Quarantine if configured
        if monitor.config.quarantineCorrupted:
          discard quarantineCorruptedFile(event.path, violation)

    of "created":
      # Log new file creation in monitored areas
      if event.path.contains("/Programs/"):
        logGlobalSecurityEvent(EventFileSystemChange, SeverityInfo, "integrity-monitor",
          fmt"New file created in Programs: {event.path}")

    of "deleted":
      # Log file deletion in monitored areas
      if event.path.contains("/Programs/"):
        logGlobalSecurityEvent(EventFileSystemChange, SeverityWarning, "integrity-monitor",
          fmt"File deleted from Programs: {event.path}")

  except Exception as e:
    errorLog(fmt"Error processing file watch event: {e.msg}")

proc extractPackageName*(filePath: string): string =
  ## Extract package name from file path
  try:
    let pathParts = filePath.split("/")
    for i, part in pathParts:
      if part == "Programs" and i + 1 < pathParts.len:
        return pathParts[i + 1]
    return "unknown"
  except:
    return "unknown"

proc startPeriodicIntegrityScans*(monitor: var IntegrityMonitor, config: PeriodicScanConfig) {.async.} =
  ## Start periodic integrity scans with configurable scheduling
  if not config.enabled:
    return

  logGlobalSecurityEvent(EventSystemStartup, SeverityInfo, "integrity-monitor",
    fmt"Starting periodic integrity scans (interval: {config.intervalSeconds}s)")

  var lastFullScan = default(times.DateTime)
  var lastIncrementalScan = default(times.DateTime)

  while monitor.monitoringEnabled:
    try:
      let currentTime = now()
      let currentHour = currentTime.hour

      # Check if it's time for a full scan
      let shouldRunFullScan = (currentHour == config.fullScanHour and
                              (lastFullScan == default(times.DateTime) or
                               (currentTime - lastFullScan).inDays >= 1))

      # Check if it's time for an incremental scan
      let shouldRunIncrementalScan = (lastIncrementalScan == default(times.DateTime) or
                                     (currentTime - lastIncrementalScan).inMinutes >= config.incrementalScanMinutes)

      if shouldRunFullScan:
        showInfo("🔍 Starting scheduled full system integrity scan...")
        let results = verifyAllPackages(monitor)
        lastFullScan = currentTime

        # Log scan results
        let failedCount = results.countIt(not it.success)
        if failedCount == 0:
          logGlobalSecurityEvent(EventSystemHealthCheck, SeverityInfo, "integrity-monitor",
            fmt"Scheduled full integrity scan completed: {results.len} packages verified, all passed")
        else:
          logGlobalSecurityEvent(EventSystemHealthCheck, SeverityWarning, "integrity-monitor",
            fmt"Scheduled full integrity scan completed: {failedCount} of {results.len} packages failed")

      elif shouldRunIncrementalScan:
        # Incremental scan - only check recently modified packages
        showInfo("🔍 Starting scheduled incremental integrity scan...")
        let recentlyModified = findRecentlyModifiedPackages(monitor, config.incrementalScanMinutes)

        if recentlyModified.len > 0:
          var incrementalResults: seq[IntegrityCheckResult] = @[]
          for packagePath in recentlyModified:
            let packageName = extractPackageName(packagePath)
            incrementalResults.add(verifyPackageIntegrity(packageName, packagePath))

          lastIncrementalScan = currentTime

          let failedCount = incrementalResults.countIt(not it.success)
          logGlobalSecurityEvent(EventSystemHealthCheck, SeverityInfo, "integrity-monitor",
            fmt"Incremental integrity scan: {incrementalResults.len} packages checked, {failedCount} failed")

      # Sleep until next check
      await sleepAsync(60000)  # Check every minute

    except Exception as e:
      logGlobalSecurityEvent(EventSecurityIncident, SeverityError, "integrity-monitor",
        fmt"Periodic scan error: {e.msg}")
      await sleepAsync(300000)  # Wait 5 minutes on error

proc findRecentlyModifiedPackages*(monitor: IntegrityMonitor, minutesBack: int): seq[string] =
  ## Find packages modified within the specified time window
  var recentPackages: seq[string] = @[]
  let cutoffTime = now().toTime() - initDuration(minutes = minutesBack)

  try:
    if dirExists("/Programs"):
      for packageDir in walkDirs("/Programs/*"):
        for versionDir in walkDirs(packageDir / "*"):
          for file in walkDirRec(versionDir):
            try:
              let modTime = getLastModificationTime(file)
              if modTime >= cutoffTime:
                let packageFile = versionDir / (extractFilename(packageDir) & ".npk")
                if fileExists(packageFile) and packageFile notin recentPackages:
                  recentPackages.add(packageFile)
                break  # Found recent modification in this version
            except:
              continue
  except Exception as e:
    errorLog(fmt"Error finding recently modified packages: {e.msg}")

  return recentPackages

proc detectTamperAttempt*(filePath: string, expectedHash: string): Option[IntegrityViolation] =
  ## Detect if a file has been tampered with
  try:
    if not fileExists(filePath):
      return some(IntegrityViolation(
        violationType: "file_deleted",
        packageName: extractFilename(parentDir(filePath)),
        filePath: filePath,
        expectedHash: expectedHash,
        actualHash: "",
        detectedAt: now().utc(),
        severity: SeverityCritical
      ))

    # Compute current hash
    let hashResult = computeFileHash(filePath, HashBlake2b)
    let currentHash = formatHashString(hashResult.algorithm, hashResult.digest)

    if currentHash != expectedHash:
      return some(IntegrityViolation(
        violationType: "file_modified",
        packageName: extractFilename(parentDir(filePath)),
        filePath: filePath,
        expectedHash: expectedHash,
        actualHash: currentHash,
        detectedAt: now().utc(),
        severity: SeverityCritical
      ))

  except Exception:
    return some(IntegrityViolation(
      violationType: "check_failed",
      packageName: "unknown",
      filePath: filePath,
      expectedHash: expectedHash,
      actualHash: "error",
      detectedAt: now().utc(),
      severity: SeverityError
    ))

  return none(IntegrityViolation)

# =============================================================================
# CLI Command Implementations
# =============================================================================

proc nipVerifyCommand*(target: string, checkSignatures: bool = true,
                      verbose: bool = false): seq[IntegrityCheckResult] =
  ## Implement nip verify <package|--all> command
  var results: seq[IntegrityCheckResult] = @[]

  let monitor = newIntegrityMonitor(getDefaultIntegrityConfig())

  if target == "--all" or target == "all":
    # Verify all packages
    results = verifyAllPackages(monitor)
  else:
    # Verify specific package
    let packagePath = fmt"/Programs/{target}/current/{target}.npk"
    if fileExists(packagePath):
      results.add(verifyPackageIntegrity(target, packagePath))

      if checkSignatures:
        let config = getDefaultKeyringConfig()
        var keyringManager = newKeyringManager(config)
        keyringManager.loadAllKeyrings()
        results.add(verifyPackageSignature(target, packagePath, keyringManager))
    else:
      results.add(IntegrityCheckResult(
        checkType: CheckFileIntegrity,
        packageName: target,
        success: false,
        message: fmt"Package not found: {target}",
        details: %*{"package_path": packagePath},
        checkTime: now().utc(),
        duration: 0.0
      ))

  return results

proc nipDoctorIntegrityCommand*(autoRepair: bool = false): IntegrityCheckResult =
  ## Implement nip doctor --integrity command
  let monitor = newIntegrityMonitor(getDefaultIntegrityConfig())
  let result = runIntegrityHealthCheck(monitor)

  # Log health check result
  let severity = if result.success: SeverityInfo else: SeverityError
  logGlobalSecurityEvent(EventPackageVerification, severity, "integrity-monitor",
    fmt"System integrity check: {result.message}")

  # Attempt auto-repair if enabled and issues found
  if autoRepair and not result.success:
    # TODO: Implement auto-repair logic
    discard

  return result

# =============================================================================
# Integration with runHealthChecks() Framework
# =============================================================================

type
  HealthCheckFunction* = proc(): IntegrityCheckResult

  RegisteredHealthCheck* = object
    name*: string
    description*: string
    checkFunction*: HealthCheckFunction
    intervalSeconds*: int
    lastRun*: times.DateTime
    enabled*: bool

var registeredHealthChecks*: seq[RegisteredHealthCheck] = @[]

proc registerIntegrityHealthCheck*(name: string, description: string,
                                  checkFunction: HealthCheckFunction,
                                  intervalSeconds: int = 3600) =
  ## Register a health check function with the framework
  let healthCheck = RegisteredHealthCheck(
    name: name,
    description: description,
    checkFunction: checkFunction,
    intervalSeconds: intervalSeconds,
    lastRun: default(times.DateTime),
    enabled: true
  )

  registeredHealthChecks.add(healthCheck)

  logGlobalSecurityEvent(EventSystemStartup, SeverityInfo, "health-check-framework",
    fmt"Registered health check: {name} (interval: {intervalSeconds}s)")

proc runHealthChecks*(): seq[IntegrityCheckResult] =
  ## Run all registered health checks that are due
  var results: seq[IntegrityCheckResult] = @[]
  let currentTime = now()

  for i, healthCheck in registeredHealthChecks.mpairs:
    if not healthCheck.enabled:
      continue

    # Check if this health check is due to run
    let timeSinceLastRun = if healthCheck.lastRun == default(times.DateTime):
      int.high  # Never run before
    else:
      (currentTime - healthCheck.lastRun).inSeconds

    if timeSinceLastRun >= healthCheck.intervalSeconds:
      try:
        debugLog(fmt"Running health check: {healthCheck.name}")
        let result = healthCheck.checkFunction()
        results.add(result)
        healthCheck.lastRun = currentTime

        # Log health check result
        let severity = if result.success: SeverityInfo else: SeverityWarning
        logGlobalSecurityEvent(EventSystemHealthCheck, severity, "health-check-framework",
          fmt"Health check '{healthCheck.name}': {result.message}")

      except Exception as e:
        let errorResult = IntegrityCheckResult(
          checkType: CheckPackageConsistency,
          packageName: "system",
          success: false,
          message: fmt"Health check '{healthCheck.name}' failed: {e.msg}",
          details: %*{"error": e.msg},
          checkTime: currentTime,
          duration: 0.0
        )
        results.add(errorResult)

        logGlobalSecurityEvent(EventSecurityIncident, SeverityError, "health-check-framework",
          fmt"Health check '{healthCheck.name}' error: {e.msg}")

  return results

proc registerIntegrityHealthChecks*() =
  ## Register integrity checks with the health check framework

  # Register package integrity health check
  registerIntegrityHealthCheck(
    "package-integrity",
    "Verify integrity of all installed packages",
    proc(): IntegrityCheckResult =
      let monitor = newIntegrityMonitor(getDefaultIntegrityConfig())
      return runIntegrityHealthCheck(monitor),
    3600  # Run every hour
  )

  # Register keyring health check
  registerIntegrityHealthCheck(
    "keyring-health",
    "Check keyring status and key validity",
    proc(): IntegrityCheckResult =
      try:
        let config = getDefaultKeyringConfig()
        var keyringManager = newKeyringManager(config)
        keyringManager.loadAllKeyrings()

        # TODO: Implement getKeyringStatistics method in keyring_manager
        let expiredKeys = 0  # Placeholder
        let revokedKeys = 0  # Placeholder

        if expiredKeys == 0 and revokedKeys == 0:
          return IntegrityCheckResult(
            checkType: CheckKeyringHealth,
            packageName: "system",
            success: true,
            message: "Keyring health check passed",
            details: %*{"expired_keys": expiredKeys, "revoked_keys": revokedKeys},
            checkTime: now(),
            duration: 0.0
          )
        else:
          return IntegrityCheckResult(
            checkType: CheckKeyringHealth,
            packageName: "system",
            success: false,
            message: fmt"Keyring issues: {expiredKeys} expired, {revokedKeys} revoked keys",
            details: %*{"expired_keys": expiredKeys, "revoked_keys": revokedKeys},
            checkTime: now(),
            duration: 0.0
          )
      except Exception as e:
        return IntegrityCheckResult(
          checkType: CheckKeyringHealth,
          packageName: "system",
          success: false,
          message: fmt"Keyring health check failed: {e.msg}",
          details: %*{"error": e.msg},
          checkTime: now(),
          duration: 0.0
        ),
    7200  # Run every 2 hours
  )

  # Register CRL freshness check
  registerIntegrityHealthCheck(
    "crl-freshness",
    "Check Certificate Revocation List freshness",
    proc(): IntegrityCheckResult =
      try:
        # TODO: Implement actual CRL freshness check
        return IntegrityCheckResult(
          checkType: CheckCRLFreshness,
          packageName: "system",
          success: true,
          message: "CRL freshness check passed",
          details: %*{"last_update": $now()},
          checkTime: now(),
          duration: 0.0
        )
      except Exception as e:
        return IntegrityCheckResult(
          checkType: CheckCRLFreshness,
          packageName: "system",
          success: false,
          message: fmt"CRL freshness check failed: {e.msg}",
          details: %*{"error": e.msg},
          checkTime: now(),
          duration: 0.0
        ),
    21600  # Run every 6 hours
  )

proc startHealthCheckDaemon*(monitor: var IntegrityMonitor) {.async.} =
  ## Start the health check daemon that runs registered health checks
  if not monitor.monitoringEnabled:
    return

  logGlobalSecurityEvent(EventSystemStartup, SeverityInfo, "health-check-daemon",
    "Starting health check daemon")

  while monitor.monitoringEnabled:
    try:
      let results = runHealthChecks()

      if results.len > 0:
        let failedCount = results.countIt(not it.success)
        if failedCount > 0:
          logGlobalSecurityEvent(EventSystemHealthCheck, SeverityWarning, "health-check-daemon",
            fmt"Health checks completed: {failedCount} of {results.len} checks failed")
        else:
          logGlobalSecurityEvent(EventSystemHealthCheck, SeverityInfo, "health-check-daemon",
            fmt"Health checks completed: all {results.len} checks passed")

      # Sleep for 5 minutes between health check runs
      await sleepAsync(300000)

    except Exception as e:
      logGlobalSecurityEvent(EventSecurityIncident, SeverityError, "health-check-daemon",
        fmt"Health check daemon error: {e.msg}")
      await sleepAsync(60000)  # Wait 1 minute on error

proc quarantineCorruptedFile*(filePath: string, violation: IntegrityViolation): bool =
  ## Quarantine a corrupted file by moving it to quarantine directory
  try:
    let quarantineDir = "/var/lib/nip/quarantine"
    if not dirExists(quarantineDir):
      createDir(quarantineDir)

    let timestamp = $getTime().toUnix()
    let quarantineFile = quarantineDir / fmt"{extractFilename(filePath)}.{timestamp}.quarantined"

    moveFile(filePath, quarantineFile)

    logGlobalSecurityEvent(EventSecurityIncident, SeverityCritical, "integrity-monitor",
      fmt"File quarantined: {filePath} -> {quarantineFile}")

    return true

  except Exception as e:
    errorLog(fmt"Failed to quarantine file {filePath}: {e.msg}")
    return false

# =============================================================================
# Enhanced CLI Integration
# =============================================================================

proc nipVerifyAllCommand*(checkSignatures: bool = true, verbose: bool = false,
                         autoRepair: bool = false): seq[IntegrityCheckResult] =
  ## Enhanced implementation of nip verify --all command
  let monitor = newIntegrityMonitor(getDefaultIntegrityConfig())

  if verbose:
    showInfo("🔍 Starting comprehensive verification of all packages...")

  let results = verifyAllPackages(monitor)

  # Process results for auto-repair if requested
  if autoRepair:
    for result in results:
      if not result.success:
        case result.checkType:
        of CheckFileIntegrity:
          showInfo(fmt"🔧 Attempting to repair integrity issue for {result.packageName}")
          # TODO: Implement specific repair logic
          discard

        of CheckSignatureValidity:
          showInfo(fmt"🔧 Attempting to repair signature issue for {result.packageName}")
          # TODO: Implement signature repair logic
          discard

        else:
          discard

  return results

proc nipDoctorIntegrityCommand*(autoRepair: bool = false, verbose: bool = false): IntegrityCheckResult =
  ## Enhanced implementation of nip doctor --integrity command
  let monitor = newIntegrityMonitor(getDefaultIntegrityConfig())

  if verbose:
    showInfo("🩺 Running comprehensive integrity health check...")

  let result = runIntegrityHealthCheck(monitor)

  # Log the health check result
  let severity = if result.success: SeverityInfo else: SeverityError
  logGlobalSecurityEvent(EventSystemHealthCheck, severity, "nip-doctor-integrity",
    fmt"Integrity health check: {result.message}")

  # Attempt auto-repair if enabled and issues found
  if autoRepair and not result.success:
    showInfo("🔧 Attempting automatic repair of integrity issues...")

    # Extract failed packages from details
    if result.details.hasKey("issues"):
      for issue in result.details["issues"]:
        let issueStr = issue.getStr()
        if issueStr.contains("Integrity:"):
          let packageName = issueStr.split(":")[1].strip().split(" ")[0]
          showInfo(fmt"🔧 Repairing integrity for package: {packageName}")
          # TODO: Implement specific repair logic for the package
          discard

  return result

# =============================================================================
# Integrity Violation Alerts and Reporting
# =============================================================================

type
  IntegrityAlert* = object
    alertId*: string
    alertType*: string
    severity*: SecuritySeverity
    packageName*: string
    filePath*: string
    violation*: IntegrityViolation
    timestamp*: times.DateTime
    acknowledged*: bool
    autoRepaired*: bool

  IntegrityReporter* = object
    alertThreshold*: int
    alertHistory*: seq[IntegrityAlert]
    reportingEnabled*: bool
    alertHandlers*: seq[proc(alert: IntegrityAlert)]

proc newIntegrityReporter*(alertThreshold: int = 5): IntegrityReporter =
  ## Create a new integrity reporter
  IntegrityReporter(
    alertThreshold: alertThreshold,
    alertHistory: @[],
    reportingEnabled: true,
    alertHandlers: @[]
  )

proc generateAlert*(reporter: var IntegrityReporter, violation: IntegrityViolation): IntegrityAlert =
  ## Generate an integrity alert from a violation
  let alertId = fmt"alert-{getTime().toUnix()}-{violation.packageName}"

  let alert = IntegrityAlert(
    alertId: alertId,
    alertType: violation.violationType,
    severity: violation.severity,
    packageName: violation.packageName,
    filePath: violation.filePath,
    violation: violation,
    timestamp: now(),
    acknowledged: false,
    autoRepaired: false
  )

  reporter.alertHistory.add(alert)

  # Log the alert
  logGlobalSecurityEvent(EventSecurityIncident, violation.severity, "integrity-reporter",
    fmt"Integrity alert generated: {alertId} - {violation.violationType} for {violation.packageName}")

  # Call alert handlers
  for handler in reporter.alertHandlers:
    try:
      handler(alert)
    except Exception as e:
      errorLog(fmt"Alert handler error: {e.msg}")

  return alert

proc reportIntegrityViolation*(reporter: var IntegrityReporter, violation: IntegrityViolation) =
  ## Report an integrity violation and generate alert if needed
  let alert = reporter.generateAlert(violation)

  # Check if we've exceeded the alert threshold
  let recentAlerts = reporter.alertHistory.filterIt(
    (now() - it.timestamp).inHours <= 24 and not it.acknowledged
  )

  if recentAlerts.len >= reporter.alertThreshold:
    logGlobalSecurityEvent(EventSecurityIncident, SeverityCritical, "integrity-reporter",
      fmt"CRITICAL: Integrity alert threshold exceeded - {recentAlerts.len} unacknowledged alerts in 24h")

    # TODO: Implement escalation procedures (email, notifications, etc.)
    discard

proc acknowledgeAlert*(reporter: var IntegrityReporter, alertId: string): bool =
  ## Acknowledge an integrity alert
  for alert in reporter.alertHistory.mitems:
    if alert.alertId == alertId:
      alert.acknowledged = true
      logGlobalSecurityEvent(EventSystemHealthCheck, SeverityInfo, "integrity-reporter",
        fmt"Alert acknowledged: {alertId}")
      return true

  return false

proc getActiveAlerts*(reporter: IntegrityReporter): seq[IntegrityAlert] =
  ## Get all active (unacknowledged) alerts
  return reporter.alertHistory.filterIt(not it.acknowledged)

proc getAlertSummary*(reporter: IntegrityReporter): JsonNode =
  ## Get summary of alerts for reporting
  let activeAlerts = reporter.getActiveAlerts()
  let totalAlerts = reporter.alertHistory.len

  var severityCounts = initTable[SecuritySeverity, int]()
  for alert in activeAlerts:
    if alert.severity in severityCounts:
      severityCounts[alert.severity] += 1
    else:
      severityCounts[alert.severity] = 1

  return %*{
    "total_alerts": totalAlerts,
    "active_alerts": activeAlerts.len,
    "acknowledged_alerts": totalAlerts - activeAlerts.len,
    "severity_breakdown": %*{
      "critical": severityCounts.getOrDefault(SeverityCritical, 0),
      "error": severityCounts.getOrDefault(SeverityError, 0),
      "warning": severityCounts.getOrDefault(SeverityWarning, 0),
      "info": severityCounts.getOrDefault(SeverityInfo, 0)
    },
    "alert_threshold": reporter.alertThreshold,
    "threshold_exceeded": activeAlerts.len >= reporter.alertThreshold
  }

# =============================================================================
# Integration with Main CLI Commands
# =============================================================================

proc startIntegrityMonitoringSystem*(config: IntegrityConfig): IntegrityMonitor =
  ## Start the complete integrity monitoring system
  var monitor = newIntegrityMonitor(config)

  # Register integrity health checks with the framework
  registerIntegrityHealthChecks()

  logGlobalSecurityEvent(EventSystemStartup, SeverityInfo, "integrity-system",
    "Integrity monitoring system started")

  return monitor

proc stopIntegrityMonitoringSystem*(monitor: var IntegrityMonitor) =
  ## Stop the integrity monitoring system
  monitor.monitoringEnabled = false

  logGlobalSecurityEvent(EventSystemStartup, SeverityInfo, "integrity-system",
    "Integrity monitoring system stopped")

# =============================================================================
# Export enhanced functions
# =============================================================================

export IntegrityAlert, IntegrityReporter, newIntegrityReporter
export generateAlert, reportIntegrityViolation, acknowledgeAlert
proc getHealthCheckStatus*(): JsonNode =
  ## Get status of all registered health checks
  var status = newJArray()

  for healthCheck in registeredHealthChecks:
    let timeSinceLastRun = if healthCheck.lastRun == default(times.DateTime):
      -1
    else:
      (now() - healthCheck.lastRun).inSeconds

    status.add(%*{
      "name": healthCheck.name,
      "description": healthCheck.description,
      "enabled": healthCheck.enabled,
      "interval_seconds": healthCheck.intervalSeconds,
      "last_run": if healthCheck.lastRun == default(times.DateTime): newJNull() else: %($healthCheck.lastRun),
      "seconds_since_last_run": timeSinceLastRun,
      "due_for_run": timeSinceLastRun >= healthCheck.intervalSeconds or timeSinceLastRun == -1
    })

  return %*{
    "total_checks": registeredHealthChecks.len,
    "enabled_checks": registeredHealthChecks.countIt(it.enabled),
    "checks": status
  }

# =============================================================================
# Quarantine and Repair Functions
# =============================================================================

proc attemptAutoRepair*(packageName: string, violation: IntegrityViolation): bool =
  ## Attempt to automatically repair integrity violation
  try:
    # TODO: Implement auto-repair logic
    # - Re-download package from repository
    # - Verify signature and integrity
    # - Replace corrupted file

    logGlobalSecurityEvent(EventPackageVerification, SeverityInfo, "integrity-monitor",
      fmt"Auto-repair attempted for {packageName}: {violation.violationType}")

    return false  # Not implemented yet

  except Exception as e:
    logGlobalSecurityEvent(EventSecurityIncident, SeverityError, "integrity-monitor",
      fmt"Auto-repair failed for {packageName}: {e.msg}")
    return false

# =============================================================================
# Statistics and Reporting
# =============================================================================

proc getIntegrityStatistics*(monitor: IntegrityMonitor): JsonNode =
  ## Get integrity monitoring statistics
  %*{
    "monitoring_enabled": monitor.monitoringEnabled,
    "watched_paths": monitor.watchedPaths,
    "last_full_scan": $monitor.lastFullScan,
    "violation_count": monitor.violationCount,
    "config": {
      "realtime_watcher": monitor.config.enableRealtimeWatcher,
      "scan_interval": monitor.config.scanInterval,
      "alert_threshold": monitor.config.alertThreshold,
      "auto_repair": monitor.config.autoRepair,
      "quarantine_corrupted": monitor.config.quarantineCorrupted
    }
  }

# =============================================================================
# Export main functions
# =============================================================================

export IntegrityCheckType, IntegrityCheckResult, IntegrityViolation
export IntegrityMonitor, IntegrityConfig
export newIntegrityMonitor, getDefaultIntegrityConfig
export verifyPackageIntegrity, verifyPackageSignature, verifyAllPackages
export runIntegrityHealthCheck, startFilesystemWatcher, detectTamperAttempt
export nipVerifyCommand, nipDoctorIntegrityCommand
export quarantineCorruptedFile, attemptAutoRepair, getIntegrityStatistics
export FileWatchEvent, PeriodicScanConfig, getDefaultPeriodicScanConfig
export startPeriodicIntegrityScans, findRecentlyModifiedPackages
export registerIntegrityHealthCheck, runHealthChecks, registerIntegrityHealthChecks
export startHealthCheckDaemon, getHealthCheckStatus