test_that("validateRepoName accepts valid names", {
  # Valid names should not throw errors
  expect_silent(OmopStudyBuilder:::validateRepoName("my-study"))
  expect_silent(OmopStudyBuilder:::validateRepoName("MyStudy"))
  expect_silent(OmopStudyBuilder:::validateRepoName("my_study"))
  expect_silent(OmopStudyBuilder:::validateRepoName("my.study"))
  expect_silent(OmopStudyBuilder:::validateRepoName("study-123"))
  expect_silent(OmopStudyBuilder:::validateRepoName("Study_2024.v1"))
})

test_that("validateRepoName rejects invalid names", {
  # Spaces
  expect_error(
    OmopStudyBuilder:::validateRepoName("My Study"),
    "Repository name cannot contain spaces"
  )

  # Special characters
  expect_error(
    OmopStudyBuilder:::validateRepoName("study@2024"),
    "Repository name contains invalid characters"
  )

  expect_error(
    OmopStudyBuilder:::validateRepoName("study#test"),
    "invalid characters"
  )

  # Leading hyphen
  expect_error(
    OmopStudyBuilder:::validateRepoName("-study"),
    "cannot start or end with hyphen"
  )

  # Trailing hyphen
  expect_error(
    OmopStudyBuilder:::validateRepoName("study-"),
    "cannot start or end with hyphen"
  )

  # Too long (>30 chars)
  long_name <- paste0(rep("a", 31), collapse = "")
  expect_error(
    OmopStudyBuilder:::validateRepoName(long_name),
    "Repository name too long"
  )
})

test_that("linkGitHub fails on non-existent directory", {
  expect_error(
    linkGitHub(
      directory = "nonexistent_dir_12345",
      repository = "test-repo"
    ),
    "Directory does not exist"
  )
})

test_that("linkGitHub requires repository parameter", {
  temp_dir <- tempdir()
  expect_error(
    linkGitHub(directory = temp_dir),
    "missing, with no default"
  )
})

test_that("createStudyGitIgnore creates .gitignore file", {
  temp_dir <- file.path(tempdir(), "test_gitignore")
  dir.create(temp_dir, showWarnings = FALSE, recursive = TRUE)
  on.exit(unlink(temp_dir, recursive = TRUE), add = TRUE)

  OmopStudyBuilder:::createStudyGitIgnore(temp_dir)
  expect_true(file.exists(file.path(temp_dir, ".gitignore")))
})

test_that("createStudyGitIgnore has correct content", {
  temp_dir <- file.path(tempdir(), "test_gitignore_content")
  dir.create(temp_dir, showWarnings = FALSE, recursive = TRUE)
  on.exit(unlink(temp_dir, recursive = TRUE), add = TRUE)

  OmopStudyBuilder:::createStudyGitIgnore(temp_dir)
  content <- readLines(file.path(temp_dir, ".gitignore"))

  # Check for essential patterns
  expect_true(any(grepl("results/", content, fixed = TRUE)))
  expect_true(any(grepl(".Rproj.user", content, fixed = TRUE)))
  expect_true(any(grepl(".RData", content, fixed = TRUE)))
  expect_true(any(grepl("renv/library/", content, fixed = TRUE)))
  expect_true(any(grepl(".DS_Store", content, fixed = TRUE)))
  expect_true(any(grepl("Dockerfile", content, fixed = TRUE)))

  # Check for comments
  expect_true(any(grepl("# R artifacts", content, fixed = TRUE)))
  expect_true(any(grepl("# Study outputs", content, fixed = TRUE)))
})

test_that("createStudyGitIgnore merges with existing .gitignore", {
  temp_dir <- file.path(tempdir(), "test_gitignore_merge")
  dir.create(temp_dir, showWarnings = FALSE, recursive = TRUE)
  on.exit(unlink(temp_dir, recursive = TRUE), add = TRUE)

  # Create existing .gitignore with custom content
  existing_content <- c("custom_file.txt", "my_folder/", "*.log")
  writeLines(existing_content, file.path(temp_dir, ".gitignore"))

  # Add study .gitignore
  OmopStudyBuilder:::createStudyGitIgnore(temp_dir)

  # Read final content
  final_content <- readLines(file.path(temp_dir, ".gitignore"))

  # Check custom content preserved
  expect_true("custom_file.txt" %in% final_content)
  expect_true("my_folder/" %in% final_content)
  expect_true("*.log" %in% final_content)

  # Check study content added
  expect_true(any(grepl("results/", final_content, fixed = TRUE)))
  expect_true(any(grepl(".Rproj.user", final_content, fixed = TRUE)))

  # Check no duplicates created
  expect_equal(sum(final_content == "custom_file.txt"), 1)
})

test_that("createStudyGitIgnore handles duplicate entries gracefully", {
  temp_dir <- file.path(tempdir(), "test_gitignore_duplicates")
  dir.create(temp_dir, showWarnings = FALSE, recursive = TRUE)
  on.exit(unlink(temp_dir, recursive = TRUE), add = TRUE)

  # Create existing .gitignore with some study patterns already present
  existing_content <- c(".RData", "results/", "custom.txt")
  writeLines(existing_content, file.path(temp_dir, ".gitignore"))

  # Add study .gitignore
  OmopStudyBuilder:::createStudyGitIgnore(temp_dir)

  # Read final content
  final_content <- readLines(file.path(temp_dir, ".gitignore"))

  # Check no duplicates of existing entries
  expect_equal(sum(final_content == ".RData"), 1)
  expect_equal(sum(final_content == "results/"), 1)

  # Check custom entry preserved
  expect_true("custom.txt" %in% final_content)
})

test_that("createStudyGitIgnore trims whitespace before checking duplicates", {
  temp_dir <- file.path(tempdir(), "test_gitignore_trimws")
  dir.create(temp_dir, showWarnings = FALSE, recursive = TRUE)
  on.exit(unlink(temp_dir, recursive = TRUE), add = TRUE)

  existing_content <- c(".RData   ", "  results/**/*.csv", "custom.txt  ")
  writeLines(existing_content, file.path(temp_dir, ".gitignore"))

  OmopStudyBuilder:::createStudyGitIgnore(temp_dir)

  final_content <- readLines(file.path(temp_dir, ".gitignore"))

  expect_equal(sum(final_content == ".RData"), 1)
  expect_equal(sum(final_content == "results/**/*.csv"), 1)
  expect_true("custom.txt" %in% final_content)
})

test_that("ensureGitIdentity errors when git identity is missing and user info is absent", {
  skip_if_not_installed("gert")

  temp_dir <- tempfile("test_git_identity_missing-")
  temp_home <- tempfile("git-home-")
  old_home <- Sys.getenv("HOME", unset = NA_character_)
  old_userprofile <- Sys.getenv("USERPROFILE", unset = NA_character_)

  on.exit({
    unlink(temp_dir, recursive = TRUE)
    unlink(temp_home, recursive = TRUE)
    Sys.unsetenv(c("GIT_CONFIG_NOSYSTEM", "XDG_CONFIG_HOME", "HOME", "USERPROFILE"))

    if (!is.na(old_home)) {
      Sys.setenv(HOME = old_home)
    }

    if (!is.na(old_userprofile)) {
      Sys.setenv(USERPROFILE = old_userprofile)
    }
  }, add = TRUE)

  dir.create(temp_dir, showWarnings = FALSE, recursive = TRUE)
  dir.create(temp_home, showWarnings = FALSE, recursive = TRUE)
  Sys.setenv(
    GIT_CONFIG_NOSYSTEM = "1",
    XDG_CONFIG_HOME = temp_home,
    HOME = temp_home,
    USERPROFILE = temp_home
  )

  try(gert::git_config_global_set("user.name", NULL), silent = TRUE)
  try(gert::git_config_global_set("user.email", NULL), silent = TRUE)
  gert::git_init(temp_dir)

  expect_error(
    OmopStudyBuilder:::ensureGitIdentity(temp_dir, NULL),
    "Git identity not configured and no GitHub user information was provided"
  )
})

test_that("setupGitRemote pushes the actual local branch to a bare remote", {
  skip_if_not_installed("gert")

  repo_dir <- tempfile("test-linkGitHub-local-")
  remote_dir <- tempfile("test-linkGitHub-remote-")

  on.exit({
    unlink(repo_dir, recursive = TRUE)
    unlink(remote_dir, recursive = TRUE)
  }, add = TRUE)

  dir.create(repo_dir, recursive = TRUE)
  dir.create(remote_dir, recursive = TRUE)

  gert::git_init(repo_dir)
  gert::git_init(remote_dir, bare = TRUE)
  gert::git_config_set("user.name", "Test User", repo = repo_dir)
  gert::git_config_set("user.email", "test@example.com", repo = repo_dir)

  writeLines("hello", file.path(repo_dir, "README.md"))

  expect_no_error(
    OmopStudyBuilder:::setupGitRemote(
      directory = repo_dir,
      clone_url = remote_dir,
      user_info = list(login = "test", name = "Test User", email = "test@example.com"),
      created_repo = FALSE
    )
  )

  local_branch <- gert::git_branch(repo = repo_dir)
  remote_branches <- gert::git_branch_list(repo = remote_dir)
  expect_true(local_branch %in% remote_branches$name)
})

test_that("setupGitRemote uses main branch for fresh repos", {
  skip_if_not_installed("gert")

  repo_dir <- tempfile("test-linkGitHub-local-main-")
  remote_dir <- tempfile("test-linkGitHub-remote-main-")

  on.exit({
    unlink(repo_dir, recursive = TRUE)
    unlink(remote_dir, recursive = TRUE)
  }, add = TRUE)

  dir.create(repo_dir, recursive = TRUE)
  dir.create(remote_dir, recursive = TRUE)

  gert::git_init(repo_dir)
  gert::git_init(remote_dir, bare = TRUE)
  gert::git_config_set("user.name", "Test User", repo = repo_dir)
  gert::git_config_set("user.email", "test@example.com", repo = repo_dir)

  writeLines("hello", file.path(repo_dir, "README.md"))

  expect_no_error(
    OmopStudyBuilder:::setupGitRemote(
      directory = repo_dir,
      clone_url = remote_dir,
      user_info = list(login = "test", name = "Test User", email = "test@example.com"),
      created_repo = TRUE
    )
  )

  remote_branches <- gert::git_branch_list(repo = remote_dir)
  expect_true("main" %in% remote_branches$name)
})

test_that("linkGitHub validates directory parameter", {
  expect_error(
    linkGitHub(directory = NULL, repository = "test"),
    class = "error"
  )

  expect_error(
    linkGitHub(directory = "", repository = "test"),
    "Directory does not exist"
  )
})

test_that("linkGitHub validates repository parameter", {
  temp_dir <- tempdir()

  expect_error(
    linkGitHub(directory = temp_dir, repository = NULL),
    "can not be NULL"
  )

  expect_error(
    linkGitHub(directory = temp_dir, repository = ""),
    "must have at least 1 characters"
  )
})

# ============================================================================
# MANUAL/INTEGRATION TESTS
# These tests require real GitHub authentication and network access
# Run manually with: testthat::test_file("test-linkGitHub.R", filter = "manual")
# ============================================================================

test_that("linkGitHub full workflow (MANUAL TEST - requires GITHUB_PAT)", {
  skip_if_not(Sys.getenv("RUN_MANUAL_TESTS") == "true", 
              "Manual test - set RUN_MANUAL_TESTS=true to run (requires GITHUB_PAT)")
  skip_if_not(nzchar(Sys.getenv("GITHUB_PAT")), "GITHUB_PAT not set")
  skip_if_not_installed("gh")

  # WARNING: This creates a real GitHub repository!
  # You'll need to delete it manually after testing
  test_repo_name <- paste0("test-omop-study-", format(Sys.time(), "%Y%m%d-%H%M%S"))
  temp_dir <- file.path(tempdir(), test_repo_name)
  dir.create(temp_dir, showWarnings = FALSE, recursive = TRUE)
  on.exit(unlink(temp_dir, recursive = TRUE), add = TRUE)

  # Create a dummy file to commit
  writeLines("# Test Study", file.path(temp_dir, "README.md"))

  # Run linkGitHub
  result <- linkGitHub(
    directory = temp_dir,
    repository = test_repo_name,
    organisation = NULL,  # Creates under personal account
    private = TRUE
  )

  # Verify result
  expect_true(grepl("github.com", result))
  expect_true(grepl(test_repo_name, result))

  # Cleanup: Delete the test repository
  # NOTE: You may need to delete this manually from GitHub
  message("Test repository created: ", result)
  message("Please delete manually from GitHub if needed")
})

test_that("initStudy with GitHub integration (MANUAL TEST)", {
  skip_if_not(Sys.getenv("RUN_MANUAL_TESTS") == "true", 
              "Manual test - set RUN_MANUAL_TESTS=true to run (requires GITHUB_PAT)")
  skip_if_not(nzchar(Sys.getenv("GITHUB_PAT")), "GITHUB_PAT not set")
  skip_if_not_installed("gh")

  test_repo_name <- paste0("test-init-study-", format(Sys.time(), "%Y%m%d-%H%M%S"))
  temp_dir <- file.path(tempdir(), test_repo_name)
  on.exit(unlink(temp_dir, recursive = TRUE), add = TRUE)

  # Create study with GitHub integration
  initStudy(
    directory = temp_dir,
    studyTitle = "Test Study",
    studyLeads = "Test Lead",
    repository = test_repo_name,
    organisation = NULL,
    private = TRUE
  )

  # Verify directory structure
  expect_true(dir.exists(temp_dir))
  expect_true(file.exists(file.path(temp_dir, "README.md")))
  expect_true(dir.exists(file.path(temp_dir, ".git")))
  expect_true(file.exists(file.path(temp_dir, ".gitignore")))

  message("Test repository created: https://github.com/YOUR_USERNAME/", test_repo_name)
  message("Please delete manually from GitHub")
})
