# 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.

## variant_types.nim
## Core type system for NIP variant management
## Defines typed semantic domains and variant fingerprinting

import std/[tables, times]
import config  # Import CompilerFlags

# #############################################################################
# Flag Type System
# #############################################################################

type
  FlagType* = enum
    ## Type constraint for feature flags
    ftBool        # Simple on/off: +lto, -debug
    ftChoice      # Mutually exclusive: init=dinit
    ftSet         # Multiple allowed: security=pie,relro
    ftEnum        # Predefined options: ssl=[openssl,boringssl]

  VariantFlag* = object
    ## Represents a single variant feature flag
    domain*: string        # "init", "graphics", "security"
    name*: string          # "dinit", "wayland", "pie"
    flagType*: FlagType
    enabled*: bool
    value*: string         # For choice/enum types
    affects*: seq[string]  # What this flag impacts
    conflicts*: seq[string]
    requires*: seq[string]

  CompilerFlagRule* = object
    ## Rule for resolving domain flags to compiler flags
    condition*: string     # Flag name that triggers this rule
    cflags*: string
    ldflags*: string

  FlagDomain* = object
    ## Definition of a semantic domain
    name*: string
    description*: string
    flagType*: FlagType
    exclusive*: bool
    options*: seq[string]
    default*: string
    compilerFlagRules*: Table[string, CompilerFlagRule]

# #############################################################################
# Toolchain and Target Information
# #############################################################################

type
  ToolchainInfo* = object
    ## Information about the build toolchain
    name*: string          # "gcc", "clang", "zig"
    version*: string

  TargetInfo* = object
    ## Information about the build target
    arch*: string          # "x86_64", "aarch64", "riscv64"
    os*: string            # "linux", "freebsd"


# #############################################################################
# Variant Fingerprint
# #############################################################################

type
  VariantFingerprint* = object
    ## Complete variant identification with content-addressed hash
    packageName*: string
    version*: string
    domainFlags*: Table[string, seq[string]]
    compilerFlags*: CompilerFlags
    toolchain*: ToolchainInfo
    target*: TargetInfo
    hash*: string          # blake2b-[12-char]

# #############################################################################
# Profile System
# #############################################################################

type
  VariantProfile* = object
    ## Named configuration preset for common use cases
    name*: string
    description*: string
    domains*: Table[string, seq[string]]
    compilerFlags*: CompilerFlags

# #############################################################################
# Database Record
# #############################################################################

type
  VariantRecord* = object
    ## Database record for installed variant
    fingerprint*: string
    packageName*: string
    version*: string
    domains*: Table[string, seq[string]]
    installPath*: string
    installedAt*: Time
    toolchain*: ToolchainInfo
    target*: TargetInfo

# #############################################################################
# Type Conversion and Equality Operators
# #############################################################################

proc `==`*(a, b: ToolchainInfo): bool =
  ## Compare two toolchain info objects
  a.name == b.name and a.version == b.version

proc `==`*(a, b: TargetInfo): bool =
  ## Compare two target info objects
  a.arch == b.arch and a.os == b.os

proc `==`*(a, b: VariantFlag): bool =
  ## Compare two variant flags
  a.domain == b.domain and
  a.name == b.name and
  a.flagType == b.flagType and
  a.enabled == b.enabled and
  a.value == b.value

proc `$`*(flag: VariantFlag): string =
  ## String representation of a variant flag
  let prefix = if flag.enabled: "+" else: "-"
  if flag.value.len > 0:
    result = prefix & flag.domain & "=" & flag.value
  else:
    result = prefix & flag.domain & "=" & flag.name

proc `$`*(toolchain: ToolchainInfo): string =
  ## String representation of toolchain info
  result = toolchain.name & "-" & toolchain.version

proc `$`*(target: TargetInfo): string =
  ## String representation of target info
  result = target.arch & "-" & target.os

proc `$`*(fingerprint: VariantFingerprint): string =
  ## String representation of variant fingerprint
  result = fingerprint.packageName & "/" & fingerprint.version & "-" & fingerprint.hash

# #############################################################################
# Helper Constructors
# #############################################################################

proc newToolchainInfo*(name: string, version: string): ToolchainInfo =
  ## Create a new ToolchainInfo object
  result = ToolchainInfo(name: name, version: version)

proc newTargetInfo*(arch: string, os: string): TargetInfo =
  ## Create a new TargetInfo object
  result = TargetInfo(arch: arch, os: os)

proc newVariantFlag*(domain: string, name: string, flagType: FlagType,
                     enabled: bool = true, value: string = ""): VariantFlag =
  ## Create a new VariantFlag object
  result = VariantFlag(
    domain: domain,
    name: name,
    flagType: flagType,
    enabled: enabled,
    value: value,
    affects: @[],
    conflicts: @[],
    requires: @[]
  )

proc newFlagDomain*(name: string, description: string, flagType: FlagType,
                    exclusive: bool, options: seq[string],
                    default: string = ""): FlagDomain =
  ## Create a new FlagDomain object
  result = FlagDomain(
    name: name,
    description: description,
    flagType: flagType,
    exclusive: exclusive,
    options: options,
    default: default,
    compilerFlagRules: initTable[string, CompilerFlagRule]()
  )

proc newVariantProfile*(name: string, description: string): VariantProfile =
  ## Create a new VariantProfile object
  result = VariantProfile(
    name: name,
    description: description,
    domains: initTable[string, seq[string]](),
    compilerFlags: CompilerFlags()
  )

proc newVariantRecord*(fingerprint: string, packageName: string,
                       version: string, installPath: string): VariantRecord =
  ## Create a new VariantRecord object
  result = VariantRecord(
    fingerprint: fingerprint,
    packageName: packageName,
    version: version,
    domains: initTable[string, seq[string]](),
    installPath: installPath,
    installedAt: getTime(),
    toolchain: ToolchainInfo(),
    target: TargetInfo()
  )
