test_that("setup_sandbox creates a temporary directory", {
  # Create a simple test file
  test_file <- tempfile(fileext = ".txt")
  writeLines("test content", test_file)
  on.exit(unlink(test_file))

  withr::with_dir(dirname(test_file), {
    # Setup sandbox
    sandbox <- setup_sandbox(basename(test_file))

    # Check that sandbox was created
    expect_s3_class(sandbox, "resultcheck_sandbox")
    expect_true(dir.exists(sandbox$path))
    expect_true(nchar(sandbox$id) > 0)

    # Clean up
    cleanup_sandbox(sandbox)
  })
})

test_that("setup_sandbox accepts no files argument to create an empty sandbox", {
  sandbox <- setup_sandbox()
  on.exit(cleanup_sandbox(sandbox), add = TRUE)

  expect_s3_class(sandbox, "resultcheck_sandbox")
  expect_true(dir.exists(sandbox$path))
})


test_that("setup_sandbox copies files with directory structure", {
  # Create test directory structure
  temp_root <- tempfile()
  dir.create(temp_root)
  dir.create(file.path(temp_root, "data"), recursive = TRUE)

  test_file1 <- file.path(temp_root, "data", "test1.txt")
  writeLines("content 1", test_file1)

  on.exit(unlink(temp_root, recursive = TRUE))

  # Setup sandbox with working directory set to temp_root
  withr::with_dir(temp_root, {
    sandbox <- setup_sandbox(c("data/test1.txt"))
    on.exit(cleanup_sandbox(sandbox), add = TRUE)

    # Check that file was copied with directory structure
    expect_true(file.exists(file.path(sandbox$path, "data", "test1.txt")))

    # Check content
    copied_content <- readLines(file.path(sandbox$path, "data", "test1.txt"))
    expect_equal(copied_content, "content 1")
  })
})


test_that("setup_sandbox handles custom temp base", {
  # Create custom temp base
  custom_base <- tempfile()
  dir.create(custom_base)
  on.exit(unlink(custom_base, recursive = TRUE))

  # Create a test file
  test_file <- tempfile(fileext = ".txt")
  writeLines("test", test_file)
  on.exit(unlink(test_file), add = TRUE)
  withr::with_dir(dirname(test_file), {
    # Setup sandbox with custom base
    sandbox <- setup_sandbox(basename(test_file), temp_base = custom_base)
    on.exit(cleanup_sandbox(sandbox), add = TRUE)

    # Check that sandbox is in custom base
    expect_true(grepl(custom_base, sandbox$path, fixed = TRUE))
  })
})


test_that("setup_sandbox warns about missing files", {
  expect_warning(
    sandbox <- setup_sandbox("nonexistent_file.txt"),
    "File not found"
  )

  # Clean up if sandbox was created
  if (exists("sandbox")) {
    cleanup_sandbox(sandbox)
  }
})


test_that("setup_sandbox stores last sandbox in package environment", {
  test_file <- tempfile(fileext = ".txt")
  writeLines("test", test_file)
  on.exit(unlink(test_file))
  withr::with_dir(dirname(test_file), {
    sandbox <- setup_sandbox(basename(test_file))
    on.exit(cleanup_sandbox(sandbox), add = TRUE)

    # Check that it's stored
    expect_identical(resultcheck:::.resultcheck_env$last_sandbox, sandbox)
  })
})


test_that("run_in_sandbox executes script in sandbox directory", {
  skip_if_not_installed("withr")

  # Create a test script
  script_file <- tempfile(fileext = ".R")
  writeLines(
    c(
      'writeLines("test output", "output.txt")',
      'saveRDS(getwd(), "wd.rds")'
    ),
    script_file
  )
  on.exit(unlink(script_file))

  # Create sandbox
  sandbox <- setup_sandbox(character(0))
  on.exit(cleanup_sandbox(sandbox), add = TRUE)

  # Run script in sandbox
  expect_true(run_in_sandbox(script_file, sandbox))

  # Check that output was created in sandbox
  expect_true(file.exists(file.path(sandbox$path, "output.txt")))

  # Check that script ran in sandbox directory
  saved_wd <- readRDS(file.path(sandbox$path, "wd.rds"))
  expect_equal(normalizePath(saved_wd), normalizePath(sandbox$path))
})


test_that("run_in_sandbox uses last sandbox by default", {
  skip_if_not_installed("withr")

  # Create a test script
  script_file <- tempfile(fileext = ".R")
  writeLines('writeLines("test", "output.txt")', script_file)
  on.exit(unlink(script_file))

  # Create sandbox (which becomes the last sandbox)
  sandbox <- setup_sandbox(character(0))
  on.exit(cleanup_sandbox(sandbox), add = TRUE)

  # Run without specifying sandbox
  expect_true(run_in_sandbox(script_file))

  # Check that output was created
  expect_true(file.exists(file.path(sandbox$path, "output.txt")))
})


test_that("run_in_sandbox suppresses messages and warnings", {
  skip_if_not_installed("withr")

  # Create a test script with messages and warnings
  script_file <- tempfile(fileext = ".R")
  writeLines(
    c(
      'message("This is a message")',
      'warning("This is a warning")'
    ),
    script_file
  )
  on.exit(unlink(script_file))

  # Create sandbox
  sandbox <- setup_sandbox(character(0))
  on.exit(cleanup_sandbox(sandbox), add = TRUE)

  # Run with suppression (default) - should not show messages/warnings
  result <- expect_silent(run_in_sandbox(script_file, sandbox))
  expect_true(result)
})


test_that("run_in_sandbox errors on missing script", {
  sandbox <- setup_sandbox(character(0))
  on.exit(cleanup_sandbox(sandbox), add = TRUE)

  expect_error(
    run_in_sandbox("nonexistent_script.R", sandbox),
    "Script file not found"
  )
})


test_that("run_in_sandbox errors without sandbox", {
  # Clear last sandbox
  resultcheck:::.reset_last_sandbox()

  script_file <- tempfile(fileext = ".R")
  writeLines('1 + 1', script_file)
  on.exit(unlink(script_file))

  expect_error(
    run_in_sandbox(script_file),
    "No sandbox specified"
  )
})


test_that("cleanup_sandbox removes directory", {
  test_file <- tempfile(fileext = ".txt")
  writeLines("test", test_file)
  on.exit(unlink(test_file))

  withr::with_dir(dirname(test_file), {
    sandbox <- setup_sandbox(basename(test_file))

    # Check directory exists
    expect_true(dir.exists(sandbox$path))

    # Clean up
    result <- cleanup_sandbox(sandbox)

    # Check directory is gone
    expect_false(dir.exists(sandbox$path))
    expect_true(result)
  })
})


test_that("cleanup_sandbox clears last_sandbox", {
  test_file <- tempfile(fileext = ".txt")
  writeLines("test", test_file)
  on.exit(unlink(test_file))

  withr::with_dir(dirname(test_file), {
    sandbox <- setup_sandbox(basename(test_file))

    # Verify it's stored
    expect_false(is.null(resultcheck:::.resultcheck_env$last_sandbox))

    # Clean up
    cleanup_sandbox(sandbox)

    # Check it's cleared
    expect_null(resultcheck:::.resultcheck_env$last_sandbox)
  })
})


test_that("cleanup_sandbox uses last sandbox by default", {
  test_file <- tempfile(fileext = ".txt")
  writeLines("test", test_file)
  on.exit(unlink(test_file))

  withr::with_dir(dirname(test_file), {
    sandbox <- setup_sandbox(basename(test_file))
    sandbox_path <- sandbox$path

    # Clean up without specifying sandbox
    cleanup_sandbox()

    # Check directory is gone
    expect_false(dir.exists(sandbox_path))
  })
})


test_that("cleanup_sandbox handles nonexistent directory gracefully", {
  test_file <- tempfile(fileext = ".txt")
  writeLines("test", test_file)
  on.exit(unlink(test_file))

  withr::with_dir(dirname(test_file), {
    sandbox <- setup_sandbox(basename(test_file))

    # Manually delete directory
    unlink(sandbox$path, recursive = TRUE)

    # Should warn but not error
    expect_warning(
      result <- cleanup_sandbox(sandbox),
      "does not exist"
    )
    expect_false(result)
  })
})


test_that("Full workflow: setup, run, cleanup", {
  skip_if_not_installed("withr")

  # Create test data file
  data_file <- tempfile(fileext = ".rds")
  saveRDS(data.frame(x = 1:5, y = 6:10), data_file)
  on.exit(unlink(data_file))

  withr::with_dir(dirname(data_file), {
    # Create test script
    script_file <- tempfile(fileext = ".R")
    writeLines(
      c(
        sprintf('data <- readRDS("%s")', basename(data_file)),
        'data$z <- data$x + data$y',
        'saveRDS(data, "output.rds")'
      ),
      script_file
    )
    on.exit(unlink(script_file), add = TRUE)

    # Full workflow
    sandbox <- setup_sandbox(basename(data_file))
    expect_true(run_in_sandbox(script_file, sandbox))

    # Verify output
    output_file <- file.path(sandbox$path, "output.rds")
    expect_true(file.exists(output_file))

    result <- readRDS(output_file)
    expect_equal(result$z, c(7, 9, 11, 13, 15))

    # Cleanup
    cleanup_sandbox(sandbox)
    expect_false(dir.exists(sandbox$path))
  })
})


test_that("setup_sandbox rejects absolute paths", {
  # Test Unix-style absolute path
  expect_error(
    setup_sandbox("/etc/passwd"),
    "Absolute paths are not allowed"
  )
  
  # Test another Unix-style absolute path
  expect_error(
    setup_sandbox("/tmp/test.txt"),
    "Absolute paths are not allowed"
  )
  
  # On Windows, test drive letter paths (will only trigger on Windows)
  if (.Platform$OS.type == "windows") {
    expect_error(
      setup_sandbox("C:/test.txt"),
      "Absolute paths are not allowed"
    )
    
    expect_error(
      setup_sandbox("D:\\test.txt"),
      "Absolute paths are not allowed"
    )
  }
})


test_that("setup_sandbox rejects path traversal attempts", {
  # Test basic path traversal
  expect_error(
    setup_sandbox("../etc/passwd"),
    "Path traversal"
  )
  
  # Test nested path traversal
  expect_error(
    setup_sandbox("data/../../etc/passwd"),
    "Path traversal"
  )
  
  # Test path traversal in middle
  expect_error(
    setup_sandbox("a/../b/file.txt"),
    "Path traversal"
  )
  
  # Test Windows-style path traversal
  expect_error(
    setup_sandbox("data\\..\\file.txt"),
    "Path traversal"
  )
})


test_that("setup_sandbox accepts legitimate filenames with double dots", {
  # Create test file with .. in filename
  temp_root <- tempfile()
  dir.create(temp_root)
  test_file <- file.path(temp_root, "file..txt")
  writeLines("content", test_file)
  on.exit(unlink(temp_root, recursive = TRUE))
  
  withr::with_dir(temp_root, {
    # Should accept filename with .. that is not a path component
    sandbox <- setup_sandbox("file..txt")
    expect_s3_class(sandbox, "resultcheck_sandbox")
    expect_true(file.exists(file.path(sandbox$path, "file..txt")))
    cleanup_sandbox(sandbox)
  })
  
  # Test nested path with filename containing ..
  temp_root2 <- tempfile()
  dir.create(temp_root2)
  dir.create(file.path(temp_root2, "subdir"))
  test_file2 <- file.path(temp_root2, "subdir", "data..csv")
  writeLines("csv,data", test_file2)
  on.exit(unlink(temp_root2, recursive = TRUE), add = TRUE)
  
  withr::with_dir(temp_root2, {
    # Should accept nested path with .. in filename
    sandbox <- setup_sandbox("subdir/data..csv")
    expect_s3_class(sandbox, "resultcheck_sandbox")
    expect_true(file.exists(file.path(sandbox$path, "subdir", "data..csv")))
    cleanup_sandbox(sandbox)
  })
})


test_that("setup_sandbox accepts valid relative paths", {
  # Create test files
  test_file <- tempfile(fileext = ".txt")
  writeLines("test content", test_file)
  on.exit(unlink(test_file))
  
  withr::with_dir(dirname(test_file), {
    # Simple basename should work
    sandbox <- setup_sandbox(basename(test_file))
    expect_s3_class(sandbox, "resultcheck_sandbox")
    cleanup_sandbox(sandbox)
  })
  
  # Test with subdirectory
  temp_root <- tempfile()
  dir.create(temp_root)
  dir.create(file.path(temp_root, "subdir"), recursive = TRUE)
  test_file2 <- file.path(temp_root, "subdir", "test.txt")
  writeLines("content", test_file2)
  on.exit(unlink(temp_root, recursive = TRUE), add = TRUE)
  
  withr::with_dir(temp_root, {
    # Relative path with subdirectory should work
    sandbox <- setup_sandbox("subdir/test.txt")
    expect_s3_class(sandbox, "resultcheck_sandbox")
    expect_true(file.exists(file.path(sandbox$path, "subdir", "test.txt")))
    cleanup_sandbox(sandbox)
  })
})


test_that("setup_sandbox copies entire directory recursively", {
  temp_root <- tempfile()
  dir.create(temp_root)
  dir.create(file.path(temp_root, "data"), recursive = TRUE)
  dir.create(file.path(temp_root, "data", "raw"), recursive = TRUE)
  writeLines("a,b\n1,2", file.path(temp_root, "data", "input.csv"))
  writeLines("x,y\n3,4", file.path(temp_root, "data", "raw", "other.csv"))
  on.exit(unlink(temp_root, recursive = TRUE))

  withr::with_dir(temp_root, {
    # Pass the directory name rather than individual file paths
    sandbox <- setup_sandbox("data")
    on.exit(cleanup_sandbox(sandbox), add = TRUE)

    expect_s3_class(sandbox, "resultcheck_sandbox")
    expect_true(file.exists(file.path(sandbox$path, "data", "input.csv")))
    expect_true(file.exists(file.path(sandbox$path, "data", "raw", "other.csv")))

    # Verify file contents were preserved
    copied <- readLines(file.path(sandbox$path, "data", "input.csv"))
    expect_equal(copied, c("a,b", "1,2"))
  })
})
