## test_variant_validator.nim
## Tests for domain validation system
## Ensures proper validation of domains, values, and constraints

import std/[unittest, tables, strutils]
import ../src/nimpak/variant_validator
import ../src/nimpak/variant_types
import ../src/nimpak/variant_domains

suite "Domain Validation Tests":

  test "Valid domain passes validation":
    let result = validateDomainExists("init")
    check result.isOk == true

  test "Invalid domain fails validation":
    let result = validateDomainExists("invalid_domain")
    check result.isOk == false
    if not result.isOk:
      check result.error of DomainValidationError

  test "Valid domain value passes validation":
    let result = validateDomainValue("init", "dinit")
    check result.isOk == true

  test "Invalid domain value fails validation":
    let result = validateDomainValue("init", "invalid_init")
    check result.isOk == false
    if not result.isOk:
      check result.error of DomainValidationError

  test "Exclusive domain with single value passes":
    let result = validateExclusiveConstraint("init", @["dinit"])
    check result.isOk == true

  test "Exclusive domain with multiple values fails":
    let result = validateExclusiveConstraint("init", @["dinit", "systemd"])
    check result.isOk == false
    if not result.isOk:
      check result.error of ConflictError

  test "Non-exclusive domain with multiple values passes":
    let result = validateExclusiveConstraint("security", @["pie", "relro", "hardened"])
    check result.isOk == true


suite "Domain Configuration Validation Tests":

  test "Valid configuration passes":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit"]
    domains["security"] = @["pie", "relro"]
    domains["optimization"] = @["lto"]

    let result = validateDomainConfig(domains)
    check result.isOk == true

  test "Configuration with invalid domain fails":
    var domains = initTable[string, seq[string]]()
    domains["invalid_domain"] = @["value"]

    let result = validateDomainConfig(domains)
    check result.isOk == false
    check result.error of DomainValidationError

  test "Configuration with invalid value fails":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["invalid_init_system"]

    let result = validateDomainConfig(domains)
    check result.isOk == false
    check result.error of DomainValidationError

  test "Configuration with exclusive constraint violation fails":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit", "systemd"]

    let result = validateDomainConfig(domains)
    check result.isOk == false
    check result.error of ConflictError

  test "Empty configuration passes":
    var domains = initTable[string, seq[string]]()

    let result = validateDomainConfig(domains)
    check result.isOk == true

  test "Complex valid configuration passes":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit"]
    domains["runtime"] = @["ssl", "http3", "zstd"]
    domains["security"] = @["pie", "relro", "hardened"]
    domains["optimization"] = @["lto", "march-native"]
    domains["network"] = @["ipv6", "wireguard"]

    let result = validateDomainConfig(domains)
    check result.isOk == true

suite "Variant Flag Validation Tests":

  test "Valid variant flag passes":
    let flag = newVariantFlag("init", "dinit", ftChoice, true)
    let result = validateVariantFlag(flag)
    check result.isOk == true

  test "Variant flag with invalid domain fails":
    let flag = newVariantFlag("invalid_domain", "value", ftBool, true)
    let result = validateVariantFlag(flag)
    check result.isOk == false

  test "Variant flag with invalid value fails":
    let flag = newVariantFlag("init", "invalid_init", ftChoice, true)
    let result = validateVariantFlag(flag)
    check result.isOk == false

  test "Multiple variant flags validation":
    var flags: seq[VariantFlag] = @[]
    flags.add(newVariantFlag("init", "dinit", ftChoice, true))
    flags.add(newVariantFlag("security", "pie", ftBool, true))
    flags.add(newVariantFlag("security", "relro", ftBool, true))

    let result = validateVariantFlags(flags)
    check result.isOk == true

  test "Conflicting variant flags fail":
    var flags: seq[VariantFlag] = @[]
    flags.add(newVariantFlag("init", "dinit", ftChoice, true))
    flags.add(newVariantFlag("init", "systemd", ftChoice, true))

    let result = validateVariantFlags(flags)
    check result.isOk == false

suite "Conflict Detection Tests":

  test "No conflicts in valid configuration":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit"]
    domains["security"] = @["pie", "relro"]

    let conflicts = detectConflicts(domains)
    check conflicts.len == 0
    check hasConflicts(domains) == false

  test "Detect exclusive constraint violation":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit", "systemd"]

    let conflicts = detectConflicts(domains)
    check conflicts.len > 0
    check hasConflicts(domains) == true

  test "Detect invalid domain":
    var domains = initTable[string, seq[string]]()
    domains["invalid_domain"] = @["value"]

    let conflicts = detectConflicts(domains)
    check conflicts.len > 0
    check hasConflicts(domains) == true

  test "Detect invalid value":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["invalid_init"]

    let conflicts = detectConflicts(domains)
    check conflicts.len > 0
    check hasConflicts(domains) == true

  test "Multiple conflicts detected":
    var domains = initTable[string, seq[string]]()
    domains["invalid_domain"] = @["value"]
    domains["init"] = @["dinit", "systemd"]
    domains["security"] = @["invalid_security"]

    let conflicts = detectConflicts(domains)
    check conflicts.len >= 3

suite "Validation Helper Tests":

  test "isValidConfiguration returns true for valid config":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit"]
    domains["security"] = @["pie"]

    check isValidConfiguration(domains) == true

  test "isValidConfiguration returns false for invalid config":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit", "systemd"]

    check isValidConfiguration(domains) == false

  test "getValidationErrors returns empty for valid config":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit"]

    let errors = getValidationErrors(domains)
    check errors.len == 0

  test "getValidationErrors returns errors for invalid config":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["invalid_init"]

    let errors = getValidationErrors(domains)
    check errors.len > 0

  test "validateOrThrow succeeds for valid config":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit"]

    # Should not raise
    validateOrThrow(domains)
    check true

  test "validateOrThrow raises for invalid config":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["invalid_init"]

    expect(VariantError):
      validateOrThrow(domains)

suite "Error Formatting Tests":

  test "Format domain validation error":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["invalid_init"]

    let result = validateDomainConfig(domains)
    check result.isOk == false

    let formatted = formatValidationError(result.error)
    check formatted.len > 0
    check "invalid_init" in formatted

  test "Format conflict error":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["dinit", "systemd"]

    let result = validateDomainConfig(domains)
    check result.isOk == false

    let formatted = formatValidationError(result.error)
    check formatted.len > 0
    check "exclusive" in formatted.toLowerAscii()

  test "Format all validation errors":
    var domains = initTable[string, seq[string]]()
    domains["init"] = @["invalid_init"]
    domains["security"] = @["invalid_security"]

    let formatted = formatValidationErrors(domains)
    check formatted.len > 0
    check "invalid_init" in formatted
    check "invalid_security" in formatted

when isMainModule:
  echo "Running variant validator tests..."
