# SPDX-License-Identifier: LSL-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.

# NimPak Core Types
#
# This module defines the foundational data structures for the NimPak package
# management system, following NexusOS architectural principles.

import std/[times, tables, options, json]

# =============================================================================
# Result Type for Error Handling
# =============================================================================

type
  Result*[T, E] = object
    case isOk*: bool
    of true:
      okValue*: T
    of false:
      errValue*: E

  VoidResult*[E] = object
    case isOk*: bool
    of true:
      discard
    of false:
      errValue*: E

proc ok*[T, E](val: T): Result[T, E] =
  Result[T, E](isOk: true, okValue: val)

proc ok*[E](ErrorType: typedesc[E]): VoidResult[E] =
  VoidResult[E](isOk: true)

proc err*[T, E](errVal: E): Result[T, E] =
  Result[T, E](isOk: false, errValue: errVal)

proc err*[E](errVal: E): VoidResult[E] =
  VoidResult[E](isOk: false, errValue: errVal)

proc isOk*[T, E](r: Result[T, E]): bool = r.isOk
proc isErr*[T, E](r: Result[T, E]): bool = not r.isOk
proc isOk*[E](r: VoidResult[E]): bool = r.isOk
proc isErr*[E](r: VoidResult[E]): bool = not r.isOk

proc get*[T, E](r: Result[T, E]): T =
  case r.isOk
  of true:
    r.okValue
  of false:
    raise newException(ValueError, "Attempted to get value from error result")

proc getError*[T, E](r: Result[T, E]): E =
  case r.isOk
  of false:
    r.errValue
  of true:
    raise newException(ValueError, "Attempted to get error from ok result")

proc getError*[E](r: VoidResult[E]): E =
  case r.isOk
  of false:
    r.errValue
  of true:
    raise newException(ValueError, "Attempted to get error from ok result")

proc error*[T, E](r: Result[T, E]): E =
  ## Alias for getError for convenience
  r.getError()

proc error*[E](r: VoidResult[E]): E =
  ## Alias for getError for convenience
  r.getError()

# =============================================================================
# Core Error Types
# =============================================================================

type
  NimPakError* = object of CatchableError
    code*: ErrorCode
    context*: string
    suggestions*: seq[string]

  ErrorCode* = enum
    # Access Control
    PermissionDenied, ElevationRequired, ReadOnlyViolation,
    AculViolation, PolicyViolation, TrustViolation, SignatureInvalid,

    # Network & Transport
    NetworkError, DownloadFailed, RepositoryUnavailable, TimeoutError,

    # Build & Dependency
    BuildFailed, CompilationError, MissingDependency, DependencyConflict,
    VersionMismatch, ChecksumMismatch, InvalidMetadata,

    # Storage & Integrity
    FilesystemError, CasGeneralError, GraftError, PackageNotFound, CellNotFound,
    ObjectNotFound, CorruptedObject, StorageError, CompressionError, StorageFull,
    FileReadError, FileWriteError, PackageCorrupted, ReferenceIntegrityError,

    # Runtime & Lifecycle
    TransactionFailed, RollbackFailed, GarbageCollectionFailed, UnknownError

# =============================================================================
# Package Identification and Streams
# =============================================================================

type
  PackageStream* = enum
    Stable, Testing, Dev, LTS, Custom

  PackageId* = object
    name*: string
    version*: string
    stream*: PackageStream

proc `$`*(id: PackageId): string =
  result = id.name & "-" & id.version & "[" & $id.stream & "]"

proc `==`*(a, b: PackageId): bool =
  a.name == b.name and a.version == b.version and a.stream == b.stream

# =============================================================================
# Source and Build Information
# =============================================================================

type
  SourceMethod* = enum
    Git, Http, Local, Grafted

  Source* = object
    url*: string
    hash*: string          # BLAKE2b hash, will support BLAKE3 later
    hashAlgorithm*: string # "blake2b", "blake3", etc.
    sourceMethod*: SourceMethod
    timestamp*: times.DateTime

  BuildSystemType* = enum
    CMake, Meson, Autotools, Cargo, NimBuild, Custom

# =============================================================================
# Runtime and System Configuration
# =============================================================================

type
  LibcType* = enum
    Musl, Glibc, None

  AllocatorType* = enum
    Jemalloc, Internal, GlibcMalloc, System

  RuntimeProfile* = object
    libc*: LibcType
    allocator*: AllocatorType
    systemdAware*: bool
    reproducible*: bool
    tags*: seq[string]

# =============================================================================
# ACUL Compliance
# =============================================================================

type
  AculCompliance* = object
    required*: bool
    membership*: string
    attribution*: string
    buildLog*: string

# =============================================================================
# Package Metadata
# =============================================================================

type
  PackageMetadata* = object
    description*: string
    license*: string
    maintainer*: string
    tags*: seq[string]
    runtime*: RuntimeProfile

# =============================================================================
# Fragment (Package Definition)
# =============================================================================

type
  Fragment* = object
    id*: PackageId
    source*: Source
    dependencies*: seq[PackageId]
    buildSystem*: BuildSystemType
    metadata*: PackageMetadata
    acul*: AculCompliance

# =============================================================================
# Multi-Variant OS Support
# =============================================================================

type
  OSVariant* = enum
    NexusOS, NexusBSD, NexusSafeCore, NexusUnikernel

  KernelType* = enum
    Linux, DragonflyBSD, Redox, Theseus, Unikernel

  UserspaceType* = enum
    GnuFree, Minimal, NimOnly, Custom

  LicenseModel* = enum
    MitAcul, BsdAcul, ApacheMit, EmbeddedAcul

  VariantConfig* = object
    variant*: OSVariant
    kernel*: KernelType
    libc*: LibcType
    userspace*: UserspaceType
    licenseModel*: LicenseModel

  SystemDefinition* = object
    variant*: VariantConfig
    packages*: seq[PackageId]
    configuration*: JsonNode # System-specific configuration
    immutable*: bool

# =============================================================================
# Content-Addressable Storage (CAS)
# =============================================================================

type
  CasObject* = object
    hash*: string # Multihash (BLAKE2b-512 by default)
    size*: int64
    compressed*: bool

  CasStats* = object
    objectCount*: int
    totalSize*: int64
    compressionRatio*: float

  CasErrorKind* = enum
    ObjectNotFound, CorruptedObject, StorageError, CompressionError

# =============================================================================
# Package Files and Manifests
# =============================================================================

type
  FilePermissions* = object
    mode*: int
    owner*: string
    group*: string

  # Forward declarations for interdependent types
  ChunkRef* = object
    hash*: string
    offset*: int64
    size*: int
    merkleProof*: Option[MerkleProof]

  MerkleProof* = object
    ## Merkle tree proof for chunk verification
    path*: seq[string]  ## Hash path from leaf to root
    indices*: seq[int]  ## Path indices for verification

  PackageFile* = object
    path*: string
    hash*: string
    hashAlgorithm*: string # "blake2b", "blake3", etc.
    permissions*: FilePermissions
    chunks*: Option[seq[ChunkRef]] # For large files with chunk-level deduplication

  PackageManifest* = object
    files*: seq[PackageFile]
    totalSize*: int64
    created*: times.DateTime
    merkleRoot*: string # Root hash of the entire package content

# =============================================================================
# Package Format System - Core Infrastructure
# =============================================================================

type
  PackageFormat* = enum
    ## Five distinct package formats, each optimized for specific use cases
    NprRecipeFormat,    ## .npr - Source recipes (KDL, plain text, Git-friendly)
    NpkBinaryFormat,    ## .npk.zst - Compiled binary packages (tar+zstd, BLAKE3/Ed25519)
    NcaChunkFormat,     ## .nca - Content-addressable chunks (Merkle trees, optional zstd)
    NssSnapshotFormat,  ## .nss.zst - System snapshots (zstd, lockfile+manifests+logs)
    NofOverlayFormat    ## .nof - Overlay fragments (KDL, declarative overlays)

  CryptoAlgorithms* = object
    ## Quantum-resistant cryptographic algorithm metadata
    ## Explicit algorithm specification for future-proof transitions
    hashAlgorithm*: string      ## "BLAKE3", "BLAKE2b", "SHA3-512"
    signatureAlgorithm*: string ## "Ed25519", "Dilithium"
    version*: string            ## Algorithm version for compatibility tracking

  Signature* = object
    keyId*: string
    algorithm*: string
    signature*: seq[byte]

# =============================================================================
# NPK Binary Package Format (.npk.zst)
# =============================================================================

type
  NpkPackage* = object
    metadata*: Fragment
    files*: seq[PackageFile]
    manifest*: PackageManifest
    signature*: Option[Signature]
    format*: PackageFormat
    cryptoAlgorithms*: CryptoAlgorithms

# =============================================================================
# NPR Recipe Format (.npr)
# =============================================================================

type
  BuildTemplate* = object
    ## Build instruction templates for source compilation
    system*: BuildSystemType
    configureArgs*: seq[string]
    buildArgs*: seq[string]
    installArgs*: seq[string]
    environment*: Table[string, string]

  NprRecipe* = object
    metadata*: Fragment
    buildInstructions*: BuildTemplate
    signature*: Option[Signature]
    format*: PackageFormat
    cryptoAlgorithms*: CryptoAlgorithms

# =============================================================================
# NCA Content-Addressable Chunks (.nca)
# =============================================================================

type
  NcaChunk* = object
    hash*: string
    data*: seq[byte]
    compressed*: bool
    merkleProof*: MerkleProof
    format*: PackageFormat
    cryptoAlgorithms*: CryptoAlgorithms

# =============================================================================
# NSS System Snapshot Format (.nss.zst)
# =============================================================================

type
  SnapshotMetadata* = object
    description*: string
    creator*: string
    tags*: seq[string]
    size*: int64
    includedGenerations*: seq[string]

  Lockfile* = object
    ## Lockfile structure for reproducible environments
    version*: string
    generated*: times.DateTime
    systemGeneration*: string
    packages*: seq[PackageId]

  NssSnapshot* = object
    name*: string
    created*: times.DateTime
    lockfile*: Lockfile
    packages*: seq[NpkPackage]
    metadata*: SnapshotMetadata
    signature*: Option[Signature]
    format*: PackageFormat
    cryptoAlgorithms*: CryptoAlgorithms

# =============================================================================
# NOF Overlay Fragment Format (.nof)
# =============================================================================

type
  OverlayConfig* = object
    ## KDL-based overlay configuration
    name*: string
    description*: string
    targetGeneration*: Option[string]
    modifications*: JsonNode  ## Will be KDL when library is available

  NofOverlay* = object
    name*: string
    description*: string
    overlayConfig*: OverlayConfig
    signature*: Option[Signature]
    format*: PackageFormat
    cryptoAlgorithms*: CryptoAlgorithms

# =============================================================================
# Grafting and External Sources
# =============================================================================

type
  GraftSource* = enum
    Pacman, Nix, Flatpak

  GraftAuditLog* = object
    timestamp*: times.DateTime
    source*: GraftSource
    packageName*: string
    version*: string
    downloadedFilename*: string
    archiveHash*: string         # BLAKE2b hash of original archive
    hashAlgorithm*: string       # "blake2b" for integrity verification
    sourceOutput*: string        # Captured command output
    downloadUrl*: Option[string] # If determinable
    originalSize*: int64
    deduplicationStatus*: string # "New" or "Reused"
    blake2bHash*: string         # BLAKE2b hash for enhanced grafting



# =============================================================================
# System Layers and Runtime Control
# =============================================================================

type
  SystemLayer* = enum
    CoreBase, AppLayer, DesktopLayer, SystemdLayer

  LayerConfig* = object
    layer*: SystemLayer
    libc*: LibcType
    allocator*: AllocatorType
    purpose*: string
    packages*: seq[PackageId]

  CompatibilityRule* = object
    allowed*: bool
    requirements*: seq[string]
    warnings*: seq[string]

# =============================================================================
# NipCells (Per-User Environments)
# =============================================================================

type
  NexusCell* = object
    name*: string
    owner*: string
    programsDir*: string # ~/.nexus/cells/name/Programs
    indexDir*: string    # ~/.nexus/cells/name/Index
    active*: bool

# =============================================================================
# Filesystem Management
# =============================================================================

type
  SymlinkPair* = object
    source*: string # /Programs/App/Version/bin/app
    target*: string # /System/Index/bin/app

  InstallLocation* = object
    programDir*: string # /Programs/App/Version
    indexLinks*: seq[SymlinkPair]

# =============================================================================
# Transaction Management
# =============================================================================

type
  OperationKind* = enum
    CreateDir, CreateFile, CreateSymlink, RemoveFile, RemoveDir

  Operation* = object
    kind*: OperationKind
    target*: string
    data*: JsonNode

  RollbackInfo* = object
    operation*: Operation
    originalState*: JsonNode

  Transaction* = object
    id*: string
    operations*: seq[Operation]
    rollbackData*: seq[RollbackInfo]

# =============================================================================
# Generation Management
# =============================================================================

type
  Generation* = object
    id*: string
    timestamp*: times.DateTime
    packages*: seq[PackageId]
    previous*: Option[string]
    size*: int64

# =============================================================================
# Validation and Security
# =============================================================================

type
  ValidationError* = object
    field*: string
    message*: string
    suggestions*: seq[string]

  SecurityError* = object
    kind*: SecurityErrorKind
    file*: string
    details*: string

  SecurityErrorKind* = enum
    ChecksumMismatch, InvalidSignature, UntrustedKey, CorruptedData

# =============================================================================
# CLI and Output Formatting
# =============================================================================

type
  OutputFormat* = enum
    ## Supported output formats for CLI commands
    OutputPlain = "plain"
    OutputJson = "json"
    OutputYaml = "yaml"
    OutputKdl = "kdl"

  CliResult*[T] = object
    ## Result type for CLI operations
    case success*: bool
    of true:
      value*: T
      outputFormat*: OutputFormat
    of false:
      error*: NimPakError
      exitCode*: int

# =============================================================================
# Debug and Logging
# =============================================================================

proc debugLog*(message: string) =
  ## Debug logging function (placeholder)
  when defined(debug):
    echo "[DEBUG] " & message

proc errorLog*(message: string) =
  ## Error logging function (placeholder)
  echo "[ERROR] " & message

proc showInfo*(message: string) =
  ## Show informational message to user
  echo message