## nip/verify.nim
## Implementation of nip verify command for package integrity verification
##
## This module implements the nip verify command that provides comprehensive
## package integrity verification including file hashes, signatures, and ACUL compliance.

import std/[os, strutils, times, json, sequtils, strformat, algorithm]
import ../nimpak/security/[integrity_monitor, hash_verifier, signature_verifier_working, keyring_manager]
import ../nimpak/cli/core

type
  VerifyOptions* = object
    checkSignatures*: bool
    verbose*: bool
    outputFormat*: OutputFormat
    autoRepair*: bool

proc parseVerifyOptions*(args: seq[string]): (string, VerifyOptions) =
  ## Parse nip verify command arguments
  var target = ""
  var options = VerifyOptions(
    checkSignatures: true,
    verbose: false,
    outputFormat: OutputHuman,
    autoRepair: false
  )

  if args.len == 0:
    raise newException(ValueError, "Usage: nip verify <package|--all> [options]")

  target = args[0]

  var i = 1
  while i < args.len:
    case args[i]:
    of "--no-signatures":
      options.checkSignatures = false
    of "--verbose", "-v":
      options.verbose = true
    of "--auto-repair":
      options.autoRepair = true
    of "--output":
      if i + 1 < args.len:
        case args[i + 1].toLower():
        of "json": options.outputFormat = OutputJson
        of "yaml": options.outputFormat = OutputYaml
        of "kdl": options.outputFormat = OutputKdl
        else: options.outputFormat = OutputHuman
        i += 1
    else:
      raise newException(ValueError, fmt"Unknown option: {args[i]}")
    i += 1

  return (target, options)

proc formatVerificationResults*(results: seq[IntegrityCheckResult], options: VerifyOptions): JsonNode =
  ## Format verification results for output
  var formattedResults = newJArray()
  var summary = %*{
    "total_checks": results.len,
    "passed": 0,
    "failed": 0,
    "total_duration": 0.0
  }

  for result in results:
    summary["total_duration"] = summary["total_duration"].getFloat() + result.duration

    if result.success:
      summary["passed"] = summary["passed"].getInt() + 1
    else:
      summary["failed"] = summary["failed"].getInt() + 1

    var resultJson = %*{
      "package": result.packageName,
      "check_type": $result.checkType,
      "success": result.success,
      "message": result.message,
      "duration": result.duration,
      "timestamp": $result.checkTime
    }

    if options.verbose:
      resultJson["details"] = result.details

    formattedResults.add(resultJson)

  return %*{
    "summary": summary,
    "results": formattedResults
  }

proc displayHumanResults*(results: seq[IntegrityCheckResult], options: VerifyOptions) =
  ## Display verification results in human-readable format
  var passed = 0
  var failed = 0
  var totalDuration = 0.0

  echo bold("Package Verification Results")
  echo "=".repeat(40)

  for result in results:
    totalDuration += result.duration

    let symbol = if result.success: success("✅") else: error("❌")
    let checkType = case result.checkType:
      of CheckFileIntegrity: "Integrity"
      of CheckSignatureValidity: "Signature"
      of CheckKeyringHealth: "Keyring"
      of CheckCRLFreshness: "CRL"
      of CheckPackageConsistency: "Consistency"
      of CheckSystemGeneration: "Generation"

    echo fmt"{symbol} {checkType}: {result.packageName}"

    if result.success:
      inc passed
      if options.verbose:
        echo fmt"    ✓ {result.message}"
        echo fmt"    ⏱ Duration: {result.duration:.3f}s"
    else:
      inc failed
      echo fmt"    ✗ {error(result.message)}"
      if options.verbose and result.details != nil:
        for key, value in result.details.pairs:
          echo fmt"    • {key}: {value}"

    if options.verbose:
      echo ""

  echo ""
  echo bold("Summary:")
  echo fmt"Total checks: {results.len}"
  echo fmt"Passed: {success($passed)}"
  echo fmt"Failed: {if failed > 0: error($failed) else: $failed}"
  echo fmt"Total time: {totalDuration:.3f}s"

  if failed > 0:
    echo ""
    echo warning("⚠️  Some verification checks failed. Run with --verbose for details.")
    if not options.autoRepair:
      echo info("💡 Use --auto-repair to attempt automatic fixes.")

proc nipVerifyCommand*(args: seq[string]): CommandResult =
  ## Main implementation of nip verify command
  try:
    let (target, options) = parseVerifyOptions(args)

    if options.verbose:
      showInfo(fmt"Starting verification of: {target}")

    # Execute verification using the integrity monitor functions
    let results = if target == "--all" or target == "all":
      # Verify all packages
      let monitor = newIntegrityMonitor(getDefaultIntegrityConfig())
      verifyAllPackages(monitor)
    else:
      # Verify specific package
      let packagePath = fmt"/Programs/{target}/current/{target}.npk"
      if fileExists(packagePath):
        var singleResult: seq[IntegrityCheckResult] = @[]
        singleResult.add(verifyPackageIntegrity(target, packagePath))

        if options.checkSignatures:
          let config = getDefaultKeyringConfig()
          var keyringManager = newKeyringManager(config)
          keyringManager.loadAllKeyrings()
          singleResult.add(verifyPackageSignature(target, packagePath, keyringManager))

        singleResult
      else:
        @[IntegrityCheckResult(
          checkType: CheckFileIntegrity,
          packageName: target,
          success: false,
          message: fmt"Package not found: {target}",
          details: %*{"package_path": packagePath},
          checkTime: now(),
          duration: 0.0
        )]

    # Handle auto-repair if requested and there are failures
    if options.autoRepair:
      for result in results:
        if not result.success and result.checkType == CheckFileIntegrity:
          showInfo(fmt"Attempting auto-repair for {result.packageName}")
          # TODO: Implement auto-repair logic
          discard

    # Format and display results
    case options.outputFormat:
    of OutputHuman:
      displayHumanResults(results, options)
    else:
      let formattedData = formatVerificationResults(results, options)
      outputData(formattedData)

    # Determine overall success
    let failedCount = results.countIt(not it.success)
    if failedCount == 0:
      return successResult(fmt"All verification checks passed ({results.len} checks)")
    else:
      return errorResult(fmt"Verification failed: {failedCount} of {results.len} checks failed", 1)

  except Exception as e:
    return errorResult(fmt"Verification error: {e.msg}")

export nipVerifyCommand, VerifyOptions, parseVerifyOptions