## test_variant_mapper.nim
## Unit tests for VariantMapper

import std/[unittest, tables, json, os]
import ../src/nimpak/build/variant_mapper

suite "VariantMapper Tests":

  test "VariantMapper initialization":
    let mapper = newVariantMapper()

    check mapper != nil
    check mapper.customMappings.len == 0

  test "Map generic variant to Nix":
    let mapper = newVariantMapper()

    let flag = mapper.mapToSource("firefox", "graphics", "wayland", "nix")

    check flag == "waylandSupport = true"

  test "Map generic variant to PKGSRC":
    let mapper = newVariantMapper()

    let flag = mapper.mapToSource("firefox", "graphics", "wayland", "pkgsrc")

    check flag == "wayland"

  test "Map generic variant to Gentoo":
    let mapper = newVariantMapper()

    let flag = mapper.mapToSource("firefox", "graphics", "wayland", "gentoo")

    check flag == "wayland"

  test "Map package-specific variant":
    let mapper = newVariantMapper()

    # Firefox has package-specific mapping for audio/pipewire
    let nixFlag = mapper.mapToSource("firefox", "audio", "pipewire", "nix")
    let pkgsrcFlag = mapper.mapToSource("firefox", "audio", "pipewire", "pkgsrc")

    check nixFlag == "pipewireSupport = true"
    check pkgsrcFlag == "pulseaudio"  # PKGSRC firefox uses pulseaudio flag

  test "Map unmapped variant":
    let mapper = newVariantMapper()

    let flag = mapper.mapToSource("test", "unknown", "value", "nix")

    check flag == ""

  test "Map all variants - all mapped":
    let mapper = newVariantMapper()

    var variants = initTable[string, seq[string]]()
    variants["graphics"] = @["wayland", "vulkan"]
    variants["audio"] = @["pipewire"]

    let (flags, unmapped) = mapper.mapAllVariants("firefox", variants, "nix")

    check flags.len == 3
    check unmapped.len == 0
    check "waylandSupport = true" in flags
    check "vulkanSupport = true" in flags
    check "pipewireSupport = true" in flags

  test "Map all variants - some unmapped":
    let mapper = newVariantMapper()

    var variants = initTable[string, seq[string]]()
    variants["graphics"] = @["wayland"]
    variants["unknown"] = @["value"]
    variants["another"] = @["unmapped"]

    let (flags, unmapped) = mapper.mapAllVariants("test", variants, "nix")

    check flags.len == 1
    check unmapped.len == 2
    check "waylandSupport = true" in flags
    check "unknown=value" in unmapped
    check "another=unmapped" in unmapped

  test "Map all variants - empty input":
    let mapper = newVariantMapper()

    let variants = initTable[string, seq[string]]()
    let (flags, unmapped) = mapper.mapAllVariants("test", variants, "nix")

    check flags.len == 0
    check unmapped.len == 0

  test "Load custom mappings - valid JSON":
    let mapper = newVariantMapper()

    # Create a temporary JSON file
    let tempFile = getTempDir() / "test-mappings.json"
    let jsonContent = %*{
      "mypackage": {
        "feature": {
          "enabled": {
            "nix": "enableFeature = true",
            "pkgsrc": "feature",
            "gentoo": "feature",
            "description": "Enable feature"
          }
        }
      }
    }

    writeFile(tempFile, jsonContent.pretty())

    mapper.loadCustomMappings(tempFile)

    check mapper.customMappings.len == 1

    let flag = mapper.mapToSource("mypackage", "feature", "enabled", "nix")
    check flag == "enableFeature = true"

    # Cleanup
    removeFile(tempFile)

  test "Load custom mappings - non-existent file":
    let mapper = newVariantMapper()

    # Should not crash
    mapper.loadCustomMappings("/non/existent/file.json")

    check mapper.customMappings.len == 0

  test "Load custom mappings - invalid JSON":
    let mapper = newVariantMapper()

    let tempFile = getTempDir() / "invalid-mappings.json"
    writeFile(tempFile, "{ invalid json }")

    # Should not crash
    mapper.loadCustomMappings(tempFile)

    check mapper.customMappings.len == 0

    # Cleanup
    removeFile(tempFile)

  test "Custom mapping precedence over generic":
    let mapper = newVariantMapper()

    # Create custom mapping that overrides generic
    let tempFile = getTempDir() / "override-mappings.json"
    let jsonContent = %*{
      "firefox": {
        "graphics": {
          "wayland": {
            "nix": "customWaylandFlag = true",
            "pkgsrc": "custom-wayland",
            "gentoo": "custom-wayland",
            "description": "Custom wayland"
          }
        }
      }
    }

    writeFile(tempFile, jsonContent.pretty())
    mapper.loadCustomMappings(tempFile)

    let flag = mapper.mapToSource("firefox", "graphics", "wayland", "nix")

    # Should use custom mapping, not generic
    check flag == "customWaylandFlag = true"

    # Cleanup
    removeFile(tempFile)

  test "Multiple packages in custom mappings":
    let mapper = newVariantMapper()

    let tempFile = getTempDir() / "multi-mappings.json"
    let jsonContent = %*{
      "package1": {
        "domain1": {
          "value1": {
            "nix": "flag1 = true",
            "pkgsrc": "flag1",
            "gentoo": "flag1"
          }
        }
      },
      "package2": {
        "domain2": {
          "value2": {
            "nix": "flag2 = true",
            "pkgsrc": "flag2",
            "gentoo": "flag2"
          }
        }
      }
    }

    writeFile(tempFile, jsonContent.pretty())
    mapper.loadCustomMappings(tempFile)

    check mapper.customMappings.len == 2

    let flag1 = mapper.mapToSource("package1", "domain1", "value1", "nix")
    let flag2 = mapper.mapToSource("package2", "domain2", "value2", "nix")

    check flag1 == "flag1 = true"
    check flag2 == "flag2 = true"

    # Cleanup
    removeFile(tempFile)

  test "Case sensitivity in package names":
    let mapper = newVariantMapper()

    # Package-specific mappings use lowercase
    let flag1 = mapper.mapToSource("Firefox", "graphics", "wayland", "nix")
    let flag2 = mapper.mapToSource("firefox", "graphics", "wayland", "nix")
    let flag3 = mapper.mapToSource("FIREFOX", "graphics", "wayland", "nix")

    # All should map to the same thing (lowercase is used internally)
    check flag1 == flag2
    check flag2 == flag3

  test "Multiple values in same domain":
    let mapper = newVariantMapper()

    var variants = initTable[string, seq[string]]()
    variants["graphics"] = @["wayland", "vulkan", "X"]

    let (flags, unmapped) = mapper.mapAllVariants("test", variants, "nix")

    check flags.len == 3
    check unmapped.len == 0
    check "waylandSupport = true" in flags
    check "vulkanSupport = true" in flags
    check "x11Support = true" in flags

  test "Different sources produce different flags":
    let mapper = newVariantMapper()

    var variants = initTable[string, seq[string]]()
    variants["graphics"] = @["wayland"]

    let (nixFlags, _) = mapper.mapAllVariants("test", variants, "nix")
    let (pkgsrcFlags, _) = mapper.mapAllVariants("test", variants, "pkgsrc")
    let (gentooFlags, _) = mapper.mapAllVariants("test", variants, "gentoo")

    check nixFlags.len == 1
    check pkgsrcFlags.len == 1
    check gentooFlags.len == 1

    check nixFlags[0] == "waylandSupport = true"
    check pkgsrcFlags[0] == "wayland"
    check gentooFlags[0] == "wayland"

  test "Optimization domain mappings":
    let mapper = newVariantMapper()

    var variants = initTable[string, seq[string]]()
    variants["optimization"] = @["lto", "pgo"]

    let (flags, unmapped) = mapper.mapAllVariants("test", variants, "nix")

    check flags.len == 2
    check unmapped.len == 0
    check "enableLTO = true" in flags
    check "enablePGO = true" in flags

  test "Security domain mappings":
    let mapper = newVariantMapper()

    var variants = initTable[string, seq[string]]()
    variants["security"] = @["pie", "hardened"]

    let (flags, unmapped) = mapper.mapAllVariants("test", variants, "gentoo")

    check flags.len == 2
    check unmapped.len == 0
    check "pie" in flags
    check "hardened" in flags

  test "Audio domain mappings":
    let mapper = newVariantMapper()

    var variants = initTable[string, seq[string]]()
    variants["audio"] = @["pipewire", "pulseaudio", "alsa"]

    let (flags, unmapped) = mapper.mapAllVariants("test", variants, "pkgsrc")

    check flags.len == 3
    check unmapped.len == 0
    check "pipewire" in flags
    check "pulseaudio" in flags
    check "alsa" in flags
