## Package Metadata Generation Module
##
## This module implements metadata.json generation for all package formats (.npk, .nip, .nexter).
## It provides complete provenance tracking from source to installation, including:
## - Source origin and maintainer information
## - Build configuration and compiler details
## - Complete audit trail with timestamps
## - Dependency tracking with build hashes
##
## Requirements: 7.1, 7.2, 7.3, 7.4, 7.5

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

type
  FormatType* = enum
    ## Package format type
    NPK = "NPK"      ## System package
    NIP = "NIP"      ## User application
    NEXTER = "NEXTER"  ## Container

  SourceInfo* = object
    ## Source origin information (Requirement 7.1)
    origin*: string           ## Source repository or download URL
    maintainer*: string       ## Package maintainer
    upstreamUrl*: string      ## Upstream project URL
    sourceHash*: string       ## xxh3 hash of source code

  BuildInfo* = object
    ## Build configuration information (Requirement 7.2)
    compilerVersion*: string      ## Compiler version used
    compilerFlags*: seq[string]   ## Compiler flags used
    targetArchitecture*: string   ## Target CPU architecture
    buildHash*: string            ## xxh3 build hash
    buildTimestamp*: DateTime     ## When the build occurred

  ProvenanceStep* = object
    ## Single step in provenance chain (Requirement 7.3)
    timestamp*: DateTime
    action*: string        ## Action performed (e.g., "source_download", "build", "installation")
    hash*: string          ## xxh3 hash of result
    verifiedBy*: string    ## Tool/version that verified this step

  ProvenanceChain* = object
    ## Complete provenance chain from source to installation (Requirement 7.3)
    sourceDownload*: ProvenanceStep
    build*: ProvenanceStep
    installation*: ProvenanceStep

  DependencyInfo* = object
    ## Dependency information with build hash
    name*: string
    version*: string
    buildHash*: string  ## xxh3 build hash of dependency

  PackageMetadata* = object
    ## Complete package metadata (Requirements 7.1-7.5)
    packageName*: string
    version*: string
    formatType*: FormatType
    source*: SourceInfo
    buildInfo*: BuildInfo
    provenance*: Option[ProvenanceChain]
    dependencies*: seq[DependencyInfo]
    createdAt*: DateTime

proc generateMetadata*(
  packageName: string,
  version: string,
  formatType: FormatType,
  source: SourceInfo,
  buildInfo: BuildInfo,
  provenance: Option[ProvenanceChain] = none(ProvenanceChain),
  dependencies: seq[DependencyInfo] = @[]
): PackageMetadata =
  ## Generate complete package metadata
  ##
  ## This function creates a PackageMetadata object with all required information
  ## for provenance tracking and audit trails.
  ##
  ## Requirements:
  ## - 7.1: Includes source origin, maintainer, upstream URL, build timestamp
  ## - 7.2: Includes compiler version, flags, target architecture, build hash
  ## - 7.3: Records complete chain from source to installation (if provided)
  ## - 7.4: Provides full audit trail
  ## - 7.5: Uses xxh3 for build hashes

  result = PackageMetadata(
    packageName: packageName,
    version: version,
    formatType: formatType,
    source: source,
    buildInfo: buildInfo,
    provenance: provenance,
    dependencies: dependencies,
    createdAt: now()
  )

proc toJson*(metadata: PackageMetadata): string =
  ## Serialize metadata to JSON format (Requirement 7.4)
  ##
  ## This enables querying and audit trail access.

  var jsonObj = %* {
    "packageName": metadata.packageName,
    "version": metadata.version,
    "formatType": $metadata.formatType,
    "source": {
      "origin": metadata.source.origin,
      "maintainer": metadata.source.maintainer,
      "upstreamUrl": metadata.source.upstreamUrl,
      "sourceHash": metadata.source.sourceHash
    },
    "buildInfo": {
      "compilerVersion": metadata.buildInfo.compilerVersion,
      "compilerFlags": metadata.buildInfo.compilerFlags,
      "targetArchitecture": metadata.buildInfo.targetArchitecture,
      "buildHash": metadata.buildInfo.buildHash,
      "buildTimestamp": metadata.buildInfo.buildTimestamp.format("yyyy-MM-dd'T'HH:mm:ss'Z'")
    },
    "dependencies": newJArray(),
    "createdAt": metadata.createdAt.format("yyyy-MM-dd'T'HH:mm:ss'Z'")
  }

  # Add dependencies
  for dep in metadata.dependencies:
    jsonObj["dependencies"].add(%* {
      "name": dep.name,
      "version": dep.version,
      "buildHash": dep.buildHash
    })

  # Add provenance chain if present
  if metadata.provenance.isSome:
    let prov = metadata.provenance.get()
    jsonObj["provenance"] = %* {
      "sourceDownload": {
        "timestamp": prov.sourceDownload.timestamp.format("yyyy-MM-dd'T'HH:mm:ss'Z'"),
        "action": prov.sourceDownload.action,
        "hash": prov.sourceDownload.hash,
        "verifiedBy": prov.sourceDownload.verifiedBy
      },
      "build": {
        "timestamp": prov.build.timestamp.format("yyyy-MM-dd'T'HH:mm:ss'Z'"),
        "action": prov.build.action,
        "hash": prov.build.hash,
        "verifiedBy": prov.build.verifiedBy
      },
      "installation": {
        "timestamp": prov.installation.timestamp.format("yyyy-MM-dd'T'HH:mm:ss'Z'"),
        "action": prov.installation.action,
        "hash": prov.installation.hash,
        "verifiedBy": prov.installation.verifiedBy
      }
    }

  result = $jsonObj

proc fromJson*(jsonStr: string): PackageMetadata =
  ## Deserialize metadata from JSON format (Requirement 7.4)

  let jsonObj = parseJson(jsonStr)

  # Parse format type
  let formatType = case jsonObj["formatType"].getStr()
    of "NPK": FormatType.NPK
    of "NIP": FormatType.NIP
    of "NEXTER": FormatType.NEXTER
    else: FormatType.NPK

  # Parse source info
  let source = SourceInfo(
    origin: jsonObj["source"]["origin"].getStr(),
    maintainer: jsonObj["source"]["maintainer"].getStr(),
    upstreamUrl: jsonObj["source"]["upstreamUrl"].getStr(),
    sourceHash: jsonObj["source"]["sourceHash"].getStr()
  )

  # Parse build info
  var compilerFlags: seq[string] = @[]
  for flag in jsonObj["buildInfo"]["compilerFlags"]:
    compilerFlags.add(flag.getStr())

  let buildInfo = BuildInfo(
    compilerVersion: jsonObj["buildInfo"]["compilerVersion"].getStr(),
    compilerFlags: compilerFlags,
    targetArchitecture: jsonObj["buildInfo"]["targetArchitecture"].getStr(),
    buildHash: jsonObj["buildInfo"]["buildHash"].getStr(),
    buildTimestamp: parse(jsonObj["buildInfo"]["buildTimestamp"].getStr(), "yyyy-MM-dd'T'HH:mm:ss'Z'")
  )

  # Parse dependencies
  var dependencies: seq[DependencyInfo] = @[]
  if jsonObj.hasKey("dependencies"):
    for dep in jsonObj["dependencies"]:
      dependencies.add(DependencyInfo(
        name: dep["name"].getStr(),
        version: dep["version"].getStr(),
        buildHash: dep["buildHash"].getStr()
      ))

  # Parse provenance if present
  var provenance = none(ProvenanceChain)
  if jsonObj.hasKey("provenance"):
    let prov = jsonObj["provenance"]
    provenance = some(ProvenanceChain(
      sourceDownload: ProvenanceStep(
        timestamp: parse(prov["sourceDownload"]["timestamp"].getStr(), "yyyy-MM-dd'T'HH:mm:ss'Z'"),
        action: prov["sourceDownload"]["action"].getStr(),
        hash: prov["sourceDownload"]["hash"].getStr(),
        verifiedBy: prov["sourceDownload"]["verifiedBy"].getStr()
      ),
      build: ProvenanceStep(
        timestamp: parse(prov["build"]["timestamp"].getStr(), "yyyy-MM-dd'T'HH:mm:ss'Z'"),
        action: prov["build"]["action"].getStr(),
        hash: prov["build"]["hash"].getStr(),
        verifiedBy: prov["build"]["verifiedBy"].getStr()
      ),
      installation: ProvenanceStep(
        timestamp: parse(prov["installation"]["timestamp"].getStr(), "yyyy-MM-dd'T'HH:mm:ss'Z'"),
        action: prov["installation"]["action"].getStr(),
        hash: prov["installation"]["hash"].getStr(),
        verifiedBy: prov["installation"]["verifiedBy"].getStr()
      )
    ))

  result = PackageMetadata(
    packageName: jsonObj["packageName"].getStr(),
    version: jsonObj["version"].getStr(),
    formatType: formatType,
    source: source,
    buildInfo: buildInfo,
    provenance: provenance,
    dependencies: dependencies,
    createdAt: parse(jsonObj["createdAt"].getStr(), "yyyy-MM-dd'T'HH:mm:ss'Z'")
  )

proc validateMetadata*(metadata: PackageMetadata): bool =
  ## Validate metadata completeness and correctness
  ##
  ## Ensures all required fields are present and hashes use xxh3 format.

  # Check required fields
  if metadata.packageName.len == 0: return false
  if metadata.version.len == 0: return false

  # Validate source info
  if metadata.source.origin.len == 0: return false
  if metadata.source.maintainer.len == 0: return false
  if metadata.source.upstreamUrl.len == 0: return false

  # Validate hashes use xxh3 format (Requirement 7.5)
  if not metadata.source.sourceHash.startsWith("xxh3-"): return false
  if not metadata.buildInfo.buildHash.startsWith("xxh3-"): return false

  # Validate dependency hashes
  for dep in metadata.dependencies:
    if not dep.buildHash.startsWith("xxh3-"): return false

  # Validate provenance hashes if present
  if metadata.provenance.isSome:
    let prov = metadata.provenance.get()
    if not prov.sourceDownload.hash.startsWith("xxh3-"): return false
    if not prov.build.hash.startsWith("xxh3-"): return false
    if not prov.installation.hash.startsWith("xxh3-"): return false

  return true
