test_that("make_mesh_entry creates correct structure", {
  vertices <- data.frame(x = c(0, 1, 2), y = c(0, 1, 2), z = c(0, 1, 2))
  faces <- data.frame(i = 1, j = 2, k = 3)

  entry <- make_mesh_entry(
    name = "test mesh",
    vertices = vertices,
    faces = faces,
    colors = c("#FF0000", "#00FF00", "#0000FF"),
    color_mode = "vertexcolor",
    opacity = 0.8,
    hover_text = "hover info"
  )

  expect_equal(entry$name, "test mesh")
  expect_equal(entry$vertices$x, c(0, 1, 2))
  expect_equal(entry$vertices$y, c(0, 1, 2))
  expect_equal(entry$vertices$z, c(0, 1, 2))
  expect_equal(entry$faces$i, 0L)
  expect_equal(entry$faces$j, 1L)
  expect_equal(entry$faces$k, 2L)
  expect_equal(entry$colorMode, "vertexcolor")
  expect_equal(entry$opacity, 0.8)
  expect_equal(entry$hoverText, "hover info")
})

test_that("make_mesh_entry includes boundary edges when provided", {
  vertices <- data.frame(x = c(0, 1, 2), y = c(0, 1, 2), z = c(0, 1, 2))
  faces <- data.frame(i = 1, j = 2, k = 3)
  boundary <- list(c(0, 1), c(1, 2))

  entry <- make_mesh_entry(
    name = "test",
    vertices = vertices,
    faces = faces,
    colors = c("#FF0000", "#00FF00", "#0000FF"),
    boundary_edges = boundary
  )

  expect_equal(entry$boundaryEdges, boundary)
})

test_that("make_mesh_entry includes edge color and width when provided", {
  vertices <- data.frame(x = c(0, 1, 2), y = c(0, 1, 2), z = c(0, 1, 2))
  faces <- data.frame(i = 1, j = 2, k = 3)

  entry <- make_mesh_entry(
    name = "test",
    vertices = vertices,
    faces = faces,
    colors = c("#FF0000", "#00FF00", "#0000FF"),
    edge_color = "#000000",
    edge_width = 2
  )

  expect_equal(entry$edgeColor, "#000000")
  expect_equal(entry$edgeWidth, 2)
})

test_that("make_mesh_entry uses default edge width of 1", {
  vertices <- data.frame(x = c(0, 1, 2), y = c(0, 1, 2), z = c(0, 1, 2))
  faces <- data.frame(i = 1, j = 2, k = 3)

  entry <- make_mesh_entry(
    name = "test",
    vertices = vertices,
    faces = faces,
    colors = c("#FF0000", "#00FF00", "#0000FF"),
    edge_color = "#000000"
  )

  expect_equal(entry$edgeWidth, 1)
})

test_that("build_subcortical_meshes creates mesh entries for each region", {
  atlas_data <- data.frame(
    label = c("Left-Caudate", "Right-Caudate"),
    colour = c("#FF0000", "#00FF00"),
    stringsAsFactors = FALSE
  )
  atlas_data$mesh <- list(
    list(
      vertices = data.frame(x = c(0, 1, 2), y = c(0, 1, 2), z = c(0, 1, 2)),
      faces = data.frame(i = c(1, 2), j = c(2, 3), k = c(3, 1))
    ),
    list(
      vertices = data.frame(x = c(3, 4, 5), y = c(3, 4, 5), z = c(3, 4, 5)),
      faces = data.frame(i = c(1, 2), j = c(2, 3), k = c(3, 1))
    )
  )

  meshes <- build_subcortical_meshes(atlas_data, "#CCCCCC")

  expect_length(meshes, 2)
  expect_equal(meshes[[1]]$name, "Left-Caudate")
  expect_equal(meshes[[2]]$name, "Right-Caudate")
  expect_equal(meshes[[1]]$colorMode, "facecolor")
})

test_that("build_subcortical_meshes handles NA colours", {
  atlas_data <- data.frame(
    label = c("region_a"),
    colour = NA_character_,
    stringsAsFactors = FALSE
  )
  atlas_data$mesh <- list(
    list(
      vertices = data.frame(x = c(0, 1, 2), y = c(0, 1, 2), z = c(0, 1, 2)),
      faces = data.frame(i = 1, j = 2, k = 3)
    )
  )

  meshes <- build_subcortical_meshes(atlas_data, "#AABBCC")

  expect_equal(unique(meshes[[1]]$colors), "#AABBCC")
})

test_that("build_subcortical_meshes skips NULL meshes", {
  atlas_data <- data.frame(
    label = c("region_a", "region_b"),
    colour = c("#FF0000", "#00FF00"),
    stringsAsFactors = FALSE
  )
  atlas_data$mesh <- list(
    NULL,
    list(
      vertices = data.frame(x = c(0, 1, 2), y = c(0, 1, 2), z = c(0, 1, 2)),
      faces = data.frame(i = 1, j = 2, k = 3)
    )
  )

  meshes <- build_subcortical_meshes(atlas_data, "#CCCCCC")

  expect_length(meshes, 1)
  expect_equal(meshes[[1]]$name, "region_b")
})

test_that("build_tract_meshes creates vertex-colored meshes", {
  atlas_data <- data.frame(
    label = c("tract_a"),
    colour = c("#FF0000"),
    stringsAsFactors = FALSE
  )
  atlas_data$mesh <- list(
    list(
      vertices = data.frame(
        x = c(0, 1, 2, 3),
        y = c(0, 1, 2, 3),
        z = c(0, 1, 2, 3)
      ),
      faces = data.frame(i = c(1, 2), j = c(2, 3), k = c(3, 4))
    )
  )

  meshes <- build_tract_meshes(atlas_data, "#CCCCCC", color_by = "colour")

  expect_length(meshes, 1)
  expect_equal(meshes[[1]]$colorMode, "vertexcolor")
  expect_equal(meshes[[1]]$name, "tract_a")
})

test_that("build_tract_meshes handles orientation coloring", {
  atlas_data <- data.frame(
    label = c("tract_a"),
    colour = c("#FF0000"),
    stringsAsFactors = FALSE
  )

  tangents <- matrix(c(1, 0, 0, 0, 1, 0, 0, 0, 1), nrow = 3, byrow = TRUE)

  atlas_data$mesh <- list(
    list(
      vertices = data.frame(x = 1:6, y = 1:6, z = 1:6),
      faces = data.frame(i = c(1, 2), j = c(2, 3), k = c(3, 4)),
      metadata = list(
        n_centerline_points = 3,
        tangents = tangents
      )
    )
  )

  meshes <- build_tract_meshes(atlas_data, "#CCCCCC", color_by = "orientation")

  expect_length(meshes, 1)
  expect_equal(meshes[[1]]$colorMode, "vertexcolor")
  expect_length(meshes[[1]]$colors, 6)
})

test_that("tangents_to_colors computes direction-based colors", {
  mesh_data <- list(
    vertices = data.frame(x = 1:6, y = 1:6, z = 1:6),
    metadata = list(
      n_centerline_points = 3,
      tangents = matrix(
        c(
          1,
          0,
          0,
          0,
          1,
          0,
          0,
          0,
          1
        ),
        nrow = 3,
        byrow = TRUE
      )
    )
  )

  colors <- tangents_to_colors(mesh_data)

  expect_length(colors, 6)
  expect_equal(colors[1], grDevices::rgb(1, 0, 0))
  expect_equal(colors[2], grDevices::rgb(1, 0, 0))
  expect_equal(colors[3], grDevices::rgb(0, 1, 0))
  expect_equal(colors[4], grDevices::rgb(0, 1, 0))
  expect_equal(colors[5], grDevices::rgb(0, 0, 1))
  expect_equal(colors[6], grDevices::rgb(0, 0, 1))
})

test_that("tangents_to_colors handles mixed directions", {
  mesh_data <- list(
    vertices = data.frame(x = 1:4, y = 1:4, z = 1:4),
    metadata = list(
      n_centerline_points = 2,
      tangents = matrix(
        c(
          1,
          1,
          0,
          0,
          1,
          1
        ),
        nrow = 2,
        byrow = TRUE
      )
    )
  )

  colors <- tangents_to_colors(mesh_data)

  expect_length(colors, 4)
  expect_true(all(grepl("^#", colors)))
})
