## nimpak/security/event_logger.nim
## Tamper-evident security event logging with revocation support
##
## This module implements the security event logging system for Task 11.1d
## with comprehensive key revocation and rollover event tracking.

import std/[times, json, os, strutils, strformat, options, random]
import ../types_fixed

type
  SecurityEventType* = enum
    EventKeyGeneration = "key_generation"
    EventKeyRevocation = "key_revocation"
    EventKeyRollover = "key_rollover"
    EventKeyExpiration = "key_expiration"
    EventSignatureVerification = "signature_verification"
    EventPackageVerification = "package_verification"
    EventTrustViolation = "trust_violation"
    EventCRLUpdate = "crl_update"
    EventSecurityIncident = "security_incident"
    EventSystemBreach = "system_breach"
    EventSystemStartup = "system_startup"
    EventSystemHealthCheck = "system_health_check"
    EventFileSystemChange = "filesystem_change"

  SecuritySeverity* = enum
    SeverityInfo = "info"
    SeverityWarning = "warning"
    SeverityError = "error"
    SeverityCritical = "critical"

  RevocationReason* = enum
    ReasonUnspecified = 0
    ReasonKeyCompromise = 1
    ReasonCACompromise = 2
    ReasonAffiliationChanged = 3
    ReasonSuperseded = 4
    ReasonCessationOfOperation = 5
    ReasonCertificateHold = 6
    ReasonPrivilegeWithdrawn = 9

  SecurityEvent* = object
    id*: string                   # Unique event ID
    timestamp*: times.DateTime    # Event timestamp (UTC)
    eventType*: SecurityEventType # Type of security event
    severity*: SecuritySeverity   # Event severity level
    source*: string               # Event source (component/user)
    message*: string              # Human-readable description
    metadata*: JsonNode           # Structured event data
    hashChainPrev*: string        # Previous event hash (for tamper evidence)
    hashChainCurrent*: string     # Current event hash
    signature*: Option[string]    # Optional cryptographic signature

  SecurityEventLogger* = object
    logPath*: string                            # Path to security log file
    casStore*: string                           # CAS store for tamper evidence
    signingKey*: Option[string]                 # Optional signing key for events
    lastEventHash*: string                      # Hash of last logged event
    eventCounter*: int64                        # Sequential event counter
    listeners*: seq[proc(event: SecurityEvent)] # Real-time event listeners

  RevocationEvent* = object
    keyId*: string
    reason*: RevocationReason
    reasonText*: string
    revocationDate*: times.DateTime
    supersededBy*: Option[string]
    affectedPackages*: seq[string]
    emergencyRevocation*: bool
    responseActions*: seq[string]

  RolloverEvent* = object
    oldKeyId*: string
    newKeyId*: string
    rolloverType*: string  # "scheduled", "emergency", "quantum-transition"
    overlapPeriod*: string # Duration string (e.g., "7d")
    affectedRepositories*: seq[string]
    validationResults*: JsonNode

# Forward declarations
proc loadLastEventHash*(logger: var SecurityEventLogger)

# =============================================================================
# Security Event Logger Initialization
# =============================================================================

proc newSecurityEventLogger*(logPath: string, casStore: string,
                             signingKey: Option[string] = none(
                                 string)): SecurityEventLogger =
  ## Create a new security event logger
  result = SecurityEventLogger(
    logPath: logPath,
    casStore: casStore,
    signingKey: signingKey,
    lastEventHash: "",
    eventCounter: 0,
    listeners: @[]
  )

  # Create log directory if it doesn't exist
  createDir(parentDir(logPath))

  # Load last event hash if log exists
  if fileExists(logPath):
    loadLastEventHash(result)

proc loadLastEventHash*(logger: var SecurityEventLogger) =
  ## Load the hash of the last logged event for chain continuity
  if not fileExists(logger.logPath):
    return

  # Read last line of log file to get previous hash
  # TODO: Implement efficient last line reading
  logger.lastEventHash = "blake3-placeholder-hash"
  logger.eventCounter = 1 # TODO: Count actual events

# =============================================================================
# Event Creation and Logging
# =============================================================================

proc createSecurityEvent*(eventType: SecurityEventType, severity: SecuritySeverity,
                         source: string, message: string,
                         metadata: JsonNode = newJNull()): SecurityEvent =
  ## Create a new security event
  let eventId = fmt"evt-{epochTime().int}-{rand(9999):04d}"

  result = SecurityEvent(
    id: eventId,
    timestamp: now().utc(),
    eventType: eventType,
    severity: severity,
    source: source,
    message: message,
    metadata: metadata,
    hashChainPrev: "", # Will be set by logger
    hashChainCurrent: "", # Will be calculated by logger
    signature: none(string)
  )

proc calculateEventHash*(event: SecurityEvent): string =
  ## Calculate tamper-evident hash for event
  let eventData = %*{
    "id": event.id,
    "timestamp": $event.timestamp,
    "type": $event.eventType,
    "severity": $event.severity,
    "source": event.source,
    "message": event.message,
    "metadata": event.metadata,
    "prev_hash": event.hashChainPrev
  }

  # TODO: Use actual BLAKE3 hash when available
  return fmt"blake3-{eventData.pretty().len:08x}"

proc logSecurityEvent*(logger: var SecurityEventLogger,
    event: var SecurityEvent) =
  ## Log a security event with tamper-evident chaining
  # Set hash chain
  event.hashChainPrev = logger.lastEventHash
  event.hashChainCurrent = calculateEventHash(event)

  # Sign event if signing key is available
  if logger.signingKey.isSome():
    # TODO: Implement event signing
    event.signature = some("ed25519-signature-placeholder")

  # Create log entry
  let logEntry = %*{
    "id": event.id,
    "timestamp": $event.timestamp,
    "event_type": $event.eventType,
    "severity": $event.severity,
    "source": event.source,
    "message": event.message,
    "metadata": event.metadata,
    "hash_chain_prev": event.hashChainPrev,
    "hash_chain_current": event.hashChainCurrent,
    "signature": event.signature,
    "counter": logger.eventCounter
  }

  # Append to log file
  let logFile = open(logger.logPath, fmAppend)
  try:
    logFile.writeLine(logEntry.pretty(indent = 0))
  finally:
    logFile.close()

  # Store in CAS for tamper evidence
  let casPath = logger.casStore / event.hashChainCurrent
  writeFile(casPath, logEntry.pretty())

  # Update logger state
  logger.lastEventHash = event.hashChainCurrent
  inc logger.eventCounter

  # Notify listeners
  for listener in logger.listeners:
    try:
      listener(event)
    except Exception as e:
      # Don't let listener failure break logging
      echo fmt"Error in security event listener: {e.msg}"

# =============================================================================
# Revocation Event Logging
# =============================================================================

proc logKeyRevocation*(logger: var SecurityEventLogger,
    revocation: RevocationEvent) =
  ## Log a key revocation event
  let metadata = %*{
    "key_id": revocation.keyId,
    "reason_code": revocation.reason.int,
    "reason_text": revocation.reasonText,
    "revocation_date": $revocation.revocationDate,
    "superseded_by": revocation.supersededBy,
    "affected_packages": revocation.affectedPackages,
    "emergency_revocation": revocation.emergencyRevocation,
    "response_actions": revocation.responseActions
  }

  let severity = if revocation.emergencyRevocation: SeverityCritical else: SeverityWarning
  let message = fmt"Key {revocation.keyId} revoked: {revocation.reasonText}"

  var event = createSecurityEvent(EventKeyRevocation, severity, "key-manager",
      message, metadata)
  logger.logSecurityEvent(event)

proc logEmergencyRevocation*(logger: var SecurityEventLogger, keyId: string,
                           reason: string, affectedPackages: seq[string]) =
  ## Log an emergency key revocation
  let revocation = RevocationEvent(
    keyId: keyId,
    reason: ReasonKeyCompromise,
    reasonText: reason,
    revocationDate: now().utc(),
    supersededBy: none(string),
    affectedPackages: affectedPackages,
    emergencyRevocation: true,
    responseActions: @["immediate_crl_update", "package_re_signing", "client_notification"]
  )

  logger.logKeyRevocation(revocation)

# =============================================================================
# Rollover Event Logging
# =============================================================================

proc logKeyRollover*(logger: var SecurityEventLogger, rollover: RolloverEvent) =
  ## Log a key rollover event
  let metadata = %*{
    "old_key_id": rollover.oldKeyId,
    "new_key_id": rollover.newKeyId,
    "rollover_type": rollover.rolloverType,
    "overlap_period": rollover.overlapPeriod,
    "affected_repositories": rollover.affectedRepositories,
    "validation_results": rollover.validationResults
  }

  let message = fmt"Key rollover: {rollover.oldKeyId} → {rollover.newKeyId}"

  var event = createSecurityEvent(EventKeyRollover, SeverityInfo, "key-manager",
      message, metadata)
  logger.logSecurityEvent(event)

proc logScheduledRollover*(logger: var SecurityEventLogger, oldKeyId: string,
                         newKeyId: string, repositories: seq[string]) =
  ## Log a scheduled key rollover
  let rollover = RolloverEvent(
    oldKeyId: oldKeyId,
    newKeyId: newKeyId,
    rolloverType: "scheduled",
    overlapPeriod: "7d",
    affectedRepositories: repositories,
    validationResults: %*{
      "packages_re_signed": 0, # Will be updated
    "client_updates": 0.0,
    "errors": []
  }
  )

  logger.logKeyRollover(rollover)

# =============================================================================
# Verification Event Logging
# =============================================================================

proc logSignatureVerification*(logger: var SecurityEventLogger, packageName: string,
                              keyId: string, success: bool,
                                  reason: string = "") =
  ## Log a signature verification event
  let metadata = %*{
    "package": packageName,
    "key_id": keyId,
    "verification_success": success,
    "failure_reason": reason,
    "timestamp": $now().utc()
  }

  let severity = if success: SeverityInfo else: SeverityError
  let message = if success:
    fmt"Signature verification succeeded for {packageName}"
  else:
    fmt"Signature verification failed for {packageName}: {reason}"

  var event = createSecurityEvent(EventSignatureVerification, severity,
      "verifier", message, metadata)
  logger.logSecurityEvent(event)

proc logTrustViolation*(logger: var SecurityEventLogger, packageName: string,
                       violation: string, keyId: string = "") =
  ## Log a trust policy violation
  let metadata = %*{
    "package": packageName,
    "violation_type": violation,
    "key_id": keyId,
    "timestamp": $now().utc()
  }

  let message = fmt"Trust violation for {packageName}: {violation}"

  var event = createSecurityEvent(EventTrustViolation, SeverityCritical,
      "trust-manager", message, metadata)
  logger.logSecurityEvent(event)

# =============================================================================
# CRL Update Event Logging
# =============================================================================

proc logCRLUpdate*(logger: var SecurityEventLogger, crlUrl: string,
                  revokedKeys: seq[string], success: bool) =
  ## Log a Certificate/Key Revocation List update
  let metadata = %*{
    "crl_url": crlUrl,
    "revoked_keys": revokedKeys,
    "update_success": success,
    "keys_count": revokedKeys.len,
    "timestamp": $now().utc()
  }

  let severity = if success: SeverityInfo else: SeverityError
  let message = if success:
    fmt"CRL updated successfully: {revokedKeys.len} revoked keys"
  else:
    fmt"CRL update failed for {crlUrl}"

  var event = createSecurityEvent(EventCRLUpdate, severity, "crl-manager",
      message, metadata)
  logger.logSecurityEvent(event)

# =============================================================================
# Security Incident Logging
# =============================================================================

proc logSecurityIncident*(logger: var SecurityEventLogger, incidentType: string,
                         description: string, affectedSystems: seq[string],
                         responseActions: seq[string]) =
  ## Log a security incident
  let metadata = %*{
    "incident_type": incidentType,
    "description": description,
    "affected_systems": affectedSystems,
    "response_actions": responseActions,
    "incident_id": "INC-" & now().format("yyyy-MM-dd") & "-" & $rand(999),
    "timestamp": $now().utc()
  }

  let message = fmt"Security incident: {incidentType} - {description}"

  var event = createSecurityEvent(EventSecurityIncident, SeverityCritical,
      "security-team", message, metadata)
  logger.logSecurityEvent(event)

# =============================================================================
# Log Verification and Integrity
# =============================================================================

proc verifyLogIntegrity*(logger: SecurityEventLogger): tuple[valid: bool,
    errors: seq[string]] =
  ## Verify the integrity of the security log hash chain
  var errors: seq[string] = @[]

  if not fileExists(logger.logPath):
    errors.add("Security log file not found")
    return (false, errors)

  # TODO: Implement full hash chain verification
  # 1. Read all events from log
  # 2. Verify hash chain continuity
  # 3. Verify event signatures if present
  # 4. Check CAS store consistency

  return (true, errors)

proc auditSecurityLog*(logger: SecurityEventLogger, startDate: times.DateTime,
                      endDate: times.DateTime): seq[SecurityEvent] =
  ## Audit security log for events in date range
  var events: seq[SecurityEvent] = @[]

  # TODO: Implement log parsing and filtering
  # 1. Parse log file
  # 2. Filter events by date range
  # 3. Verify event integrity
  # 4. Return matching events

  return events

# =============================================================================
# CLI Integration Functions
# =============================================================================

proc registerEventListener*(logger: var SecurityEventLogger, listener: proc(
    event: SecurityEvent)) =
  ## Register a listener for real-time security events
  logger.listeners.add(listener)

proc followSecurityLog*(logger: SecurityEventLogger, callback: proc(
    event: SecurityEvent)) =
  ## Follow security log in real-time (for nip audit log --follow)
  # This is now handled via registerEventListener for internal components
  # For CLI following, we would need to tail the file, but for UTCP we use the listener
  discard

proc exportSecurityLog*(logger: SecurityEventLogger, outputPath: string,
                       format: string = "json") =
  ## Export security log in specified format
  # TODO: Implement log export in JSON, KDL, or other formats
  discard

# =============================================================================
# Global Security Event Logger
# =============================================================================

var globalSecurityLogger*: SecurityEventLogger

proc initGlobalSecurityLogger*(logPath: string, casStore: string) =
  ## Initialize the global security event logger
  globalSecurityLogger = newSecurityEventLogger(logPath, casStore)

proc registerGlobalEventListener*(listener: proc(event: SecurityEvent)) =
  ## Register a listener to the global logger
  globalSecurityLogger.registerEventListener(listener)

proc logGlobalSecurityEvent*(eventType: SecurityEventType, severity: SecuritySeverity,
                           source: string, message: string,
                               metadata: JsonNode = newJNull()) =
  ## Log an event to the global security logger
  var event = createSecurityEvent(eventType, severity, source, message, metadata)
  globalSecurityLogger.logSecurityEvent(event)

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

export SecurityEventType, SecuritySeverity, RevocationReason
export SecurityEvent, SecurityEventLogger, RevocationEvent, RolloverEvent
export newSecurityEventLogger, createSecurityEvent, logSecurityEvent
export logKeyRevocation, logEmergencyRevocation, logKeyRollover, logScheduledRollover
export logSignatureVerification, logTrustViolation, logCRLUpdate, logSecurityIncident
export verifyLogIntegrity, auditSecurityLog, followSecurityLog, exportSecurityLog
export initGlobalSecurityLogger, logGlobalSecurityEvent, registerGlobalEventListener
