# SPDX-License-Identifier: LUL-1.0
# Copyright (c) 2026 Markus Maiwald
# Stewardship: Self Sovereign Society Foundation
#
# This file is part of the Nexus Sovereign Core.
# See legal/LICENSE_SOVEREIGN.md for license terms.

## Nexus Membrane: Configuration Ledger (SPEC-803)
## Implements Event Sourcing for System State.

import strutils, times, options
import kdl # Local NPK/NipBox KDL

type
  OpType* = enum
    OpAdd, OpSet, OpDel, OpMerge, OpRollback

  ConfigTx* = object
    id*: uint64
    timestamp*: uint64
    author*: string
    op*: OpType
    path*: string
    value*: Node # KDL Node for complex values

  ConfigLedger* = object
    head_tx*: uint64
    ledger_path*: string

# --- Internal: Serialization ---

proc serialize_tx*(tx: ConfigTx): string =
  ## Converts a transaction to a KDL block for the log file.
  result = "tx id=" & $tx.id & " ts=" & $tx.timestamp & " author=\"" & tx.author & "\" {\n"
  result.add "  op \"" & ($tx.op).replace("Op", "").toUpperAscii() & "\"\n"
  result.add "  path \"" & tx.path & "\"\n"
  if tx.value != nil:
    result.add tx.value.render(indent = 2)
  result.add "}\n"

# --- Primary API ---

proc ledger_append*(ledger: var ConfigLedger, op: OpType, path: string, value: Node, author: string = "root") =
  ## Appends a new transaction to the ledger.
  ledger.head_tx += 1
  let tx = ConfigTx(
    id: ledger.head_tx,
    timestamp: uint64(epochTime()),
    author: author,
    op: op,
    path: path,
    value: value
  )
  
  # TODO: SFS-backed atomic write to /Data/ledger.sfs
  let entry = serialize_tx(tx)
  echo "[LEDGER] TX Commit: ", tx.id, " (", tx.path, ")"
  # writeToFile(ledger.ledger_path, entry, append=true)

proc ledger_replay*(ledger: ConfigLedger): Node =
  ## Replays the entire log to project the current state tree.
  ## Returns the root KDL Node of the current world state.
  result = newNode("root")
  echo "[LEDGER] Replaying from 1 to ", ledger.head_tx
  # 1. Read ledger.sfs
  # 2. Parse into seq[ConfigTx]
  # 3. Apply operations sequentially to result tree
  # TODO: Implement state projection logic

proc ledger_rollback*(ledger: var ConfigLedger, target_tx: uint64) =
  ## Rolls back the system state. 
  ## Note: This appends a ROLLBACK tx rather than truncating (SPEC-803 Doctrine).
  let rb_node = newNode("rollback_target")
  rb_node.addArg(newVal(int(target_tx)))
  ledger.ledger_append(OpRollback, "system.rollback", rb_node)
