## tests/test_build_system.nim
## Unit tests for the Nimplate build system
##
## Tests type-safe build templates, build execution, caching,
## and environment isolation for all supported build systems.

import std/[unittest, os, times, strutils]
import ../src/nimpak/build_system
import ../src/nimpak/recipes

suite "Nimplate Build System Tests":

  setup:
    # Create temporary test directory
    let testDir = getTempDir() / "nip_test_build"
    createDir(testDir)

  teardown:
    # Clean up test directory
    let testDir = getTempDir() / "nip_test_build"
    if dirExists(testDir):
      removeDir(testDir)

  test "Build environment creation":
    let sourceDir = getTempDir() / "test_source"
    createDir(sourceDir)

    let env = newBuildEnvironment(sourceDir, isolated = true)

    check env.sourceDir == sourceDir
    check env.isolated == true
    check env.environment.hasKey("PREFIX")
    check env.environment.hasKey("MAKEFLAGS")
    check env.workDir.contains("nimpak_build_")

  test "Nimplate executor creation":
    let sourceDir = getTempDir() / "test_source"
    createDir(sourceDir)

    let buildTmpl = getBuildSystemDefaults(CMake)
    let executor = newNimplateExecutor(buildTmpl, sourceDir)

    check executor.buildTemplate.system == CMake
    check executor.cacheEnabled == true
    check executor.sandboxed == true
    check executor.environment.sourceDir == sourceDir

  test "CMake build template defaults":
    let buildTmpl = getBuildSystemDefaults(CMake)

    check buildTmpl.system == CMake
    check "-DCMAKE_BUILD_TYPE=Release" in buildTmpl.configureArgs
    check "--parallel" in buildTmpl.buildArgs

  test "Autotools build template defaults":
    let buildTmpl = getBuildSystemDefaults(Autotools)

    check buildTmpl.system == Autotools
    check "--prefix=/usr" in buildTmpl.configureArgs
    check "-j" in buildTmpl.buildArgs[0]  # Should contain -j for parallel make

  test "Meson build template defaults":
    let buildTmpl = getBuildSystemDefaults(Meson)

    check buildTmpl.system == Meson
    check "setup" in buildTmpl.configureArgs
    check "--buildtype=release" in buildTmpl.configureArgs

  test "Cargo build template defaults":
    let buildTmpl = getBuildSystemDefaults(Cargo)

    check buildTmpl.system == Cargo
    check "--release" in buildTmpl.buildArgs

  test "Nim build template defaults":
    let buildTmpl = getBuildSystemDefaults(NimBuild)

    check buildTmpl.system == NimBuild
    check "-d:release" in buildTmpl.buildArgs

  test "Build hash calculation":
    let sourceDir = getTempDir() / "test_source"
    createDir(sourceDir)

    let buildTmpl = getBuildSystemDefaults(CMake)
    let hash1 = calculateBuildHash(sourceDir, buildTmpl)
    let hash2 = calculateBuildHash(sourceDir, buildTmpl)

    check hash1 == hash2  # Same source and template should produce same hash
    check hash1.startsWith("build-")

  test "Build cache detection":
    let cacheDir = getTempDir() / "build_cache"
    createDir(cacheDir)

    let buildHash = "test-build-hash"

    # Initially not cached
    check isBuildCached(buildHash, cacheDir) == false

    # Create cache file
    let cacheFile = cacheDir / buildHash & ".cache"
    writeFile(cacheFile, "cached build result")

    # Now should be cached
    check isBuildCached(buildHash, cacheDir) == true

  test "Build environment isolation setup":
    let sourceDir = getTempDir() / "test_source"
    var env = newBuildEnvironment(sourceDir, isolated = true)

    setupSandbox(env)

    check env.environment.hasKey("SANDBOX")
    check env.environment["SANDBOX"] == "true"
    check env.environment.hasKey("HOME")
    check env.environment.hasKey("TMPDIR")

suite "Nimplate Build Execution Tests":

  test "Mock CMake build execution":
    # Create a mock CMake project
    let sourceDir = getTempDir() / "cmake_project"
    createDir(sourceDir)

    # Create a minimal CMakeLists.txt
    writeFile(sourceDir / "CMakeLists.txt", """
cmake_minimum_required(VERSION 3.10)
project(TestProject)
add_executable(test main.cpp)
""")

    # Create a minimal main.cpp
    writeFile(sourceDir / "main.cpp", """
#include <iostream>
int main() { std::cout << "Hello World!" << std::endl; return 0; }
""")

    let buildTmpl = getBuildSystemDefaults(CMake)
    let executor = newNimplateExecutor(buildTmpl, sourceDir)

    # This will fail in CI without CMake, but we can test the setup
    check executor.buildTemplate.system == CMake
    check executor.environment.sourceDir == sourceDir

  test "Mock Nim build execution":
    # Create a mock Nim project
    let sourceDir = getTempDir() / "nim_project"
    createDir(sourceDir)

    # Create a minimal nim file
    writeFile(sourceDir / "main.nim", """
echo "Hello from Nim!"
""")

    let buildTmpl = getBuildSystemDefaults(NimBuild)
    let executor = newNimplateExecutor(buildTmpl, sourceDir)

    check executor.buildTemplate.system == NimBuild
    check executor.environment.sourceDir == sourceDir

  test "Build result structure":
    # Test BuildResult type
    var result = BuildResult(
      success: true,
      buildTime: 1.5,
      outputSize: 1024,
      buildLog: "Build completed successfully",
      artifacts: @["/path/to/binary"],
      phase: PhaseInstall,
      exitCode: 0
    )

    check result.success == true
    check result.buildTime == 1.5
    check result.outputSize == 1024
    check result.phase == PhaseInstall
    check result.artifacts.len == 1

suite "Build System Integration Tests":

  test "Build template validation":
    let buildTmpl = getBuildSystemDefaults(CMake)
    let warnings = validateBuildInstructions(buildTmpl)

    # CMake template should be valid
    check warnings.len == 0

  test "Custom build template creation":
    let customTmpl = createBuildTemplate(
      system = Custom,
      configureArgs = @["./configure", "--enable-feature"],
      buildArgs = @["make", "-j4"],
      installArgs = @["make", "install"]
    )

    check customTmpl.system == Custom
    check customTmpl.configureArgs.len == 2
    check customTmpl.buildArgs.len == 2
    check customTmpl.installArgs.len == 2

  test "Build environment cleanup":
    let sourceDir = getTempDir() / "test_source"
    createDir(sourceDir)

    let env = newBuildEnvironment(sourceDir, isolated = true)
    let workDir = env.workDir

    # Work directory should exist
    check dirExists(workDir)

    # Clean up
    cleanupBuildEnvironment(env)

    # Work directory should be removed (if isolated)
    # Note: This might not work in all test environments
    # check not dirExists(workDir)

  test "Build cache save and load":
    let cacheDir = getTempDir() / "build_cache_test"
    let buildHash = "test-hash-123"

    let result = BuildResult(
      success: true,
      buildTime: 2.0,
      buildLog: "Test build log",
      phase: PhaseInstall
    )

    # Save to cache
    saveBuildCache(result, buildHash, cacheDir)

    # Check cache exists
    check isBuildCached(buildHash, cacheDir) == true

suite "Build System Error Handling":

  test "Invalid source directory handling":
    let invalidDir = "/nonexistent/directory"
    let buildTmpl = getBuildSystemDefaults(CMake)

    # Should handle gracefully
    let executor = newNimplateExecutor(buildTmpl, invalidDir)
    check executor.environment.sourceDir == invalidDir

  test "Build failure handling":
    # Test that build failures are properly captured
    var result = BuildResult(
      success: false,
      exitCode: 1,
      buildLog: "Build failed with error",
      phase: PhaseBuild
    )

    check result.success == false
    check result.exitCode == 1
    check "failed" in result.buildLog

when isMainModule:
  echo "🧪 Running Build System Tests..."
  echo "Testing Nimplate build templates and execution..."

  # This will run all the test suites
  discard