library(testthat)
library(cgmguru)
library(iglu)

# Use example CGM data from iglu/cgmguru
data(example_data_5_subject)

test_that("orderfast orders by id then time", {
  set.seed(123)
  shuffled <- example_data_5_subject[sample(seq_len(nrow(example_data_5_subject))), ]
  ordered <- orderfast(shuffled)
  expected <- shuffled[order(shuffled$id, shuffled$time), ]

  # Same dimensions and columns preserved
  expect_equal(nrow(ordered), nrow(shuffled))
  expect_equal(ncol(ordered), ncol(shuffled))
  expect_equal(names(ordered), names(shuffled))
  expect_identical(ordered, expected)

  # Check that data is globally ordered by id then time
  expect_true(all(order(ordered$id, ordered$time) == seq_len(nrow(ordered))))

  # Within each id, time should be non-decreasing
  by_id_ok <- by(ordered$time, ordered$id, function(tt) all(diff(as.numeric(tt)) >= 0))
  expect_true(all(unlist(by_id_ok)))
})

test_that("orderfast respects factor level ordering like base order", {
  df <- data.frame(
    id = factor(c("a", "b", "a", "b"), levels = c("b", "a")),
    time = as.POSIXct(c(
      "2024-01-01 00:30:00",
      "2024-01-01 00:15:00",
      "2024-01-01 00:15:00",
      "2024-01-01 00:30:00"
    ), tz = "UTC"),
    gl = 1:4
  )

  expect_identical(orderfast(df), df[order(df$id, df$time), ])
})

test_that("orderfast is idempotent on already ordered data", {
  already <- orderfast(example_data_5_subject)
  again <- orderfast(already)
  expect_identical(already, again)
})

test_that("orderfast handles empty data frame with required columns", {
  empty_df <- data.frame(
    id = character(0),
    time = as.POSIXct(character(0), tz = "UTC"),
    gl = numeric(0),
    stringsAsFactors = FALSE
  )
  res <- orderfast(empty_df)
  expect_true(is.data.frame(res))
  expect_equal(nrow(res), 0)
  expect_equal(names(res), names(empty_df))
})

test_that("orderfast handles ties in id and time deterministically", {
  # Create small data with deliberate ties
  df <- data.frame(
    id = c("a", "a", "b", "a", "b"),
    time = as.POSIXct(c(
      "2024-01-01 00:00:00",
      "2024-01-01 00:00:00", # tie with first row
      "2024-01-01 01:00:00",
      "2024-01-01 00:30:00",
      "2024-01-01 00:00:00"
    ), tz = "UTC"),
    gl = c(100, 110, 120, 90, 95),
    stringsAsFactors = FALSE
  )

  set.seed(1)
  df_shuffled <- df[sample(seq_len(nrow(df))), ]
  ord <- orderfast(df_shuffled)

  # Check primary ordering by id then time
  expect_true(all(order(ord$id, ord$time) == seq_len(nrow(ord))))

  # Ties kept but relative order among perfect ties may change; ensure the tied block is contiguous
  tie_block <- ord[ord$id == "a" & ord$time == as.POSIXct("2024-01-01 00:00:00", tz = "UTC"), ]
  expect_equal(nrow(tie_block), 2)
})

test_that("orderfast places NA times last within each id and preserves NAs in id", {
  df <- data.frame(
    id = c("a", NA, "a", "b", "b"),
    time = as.POSIXct(c(
      "2024-01-01 01:00:00",
      "2024-01-01 00:00:00",
      NA,
      "2024-01-01 00:00:00",
      NA
    ), tz = "UTC"),
    gl = 1:5,
    stringsAsFactors = FALSE
  )

  ord <- orderfast(df)

  # Non-NA ids should come before NA id when ordering
  expect_true(any(is.na(ord$id)))

  # Within id 'a', NA time should be placed last
  a_rows <- ord[ord$id == "a", ]
  expect_true(is.na(tail(a_rows$time, 1)))

  # Within id 'b', NA time should be placed last
  b_rows <- ord[ord$id == "b", ]
  expect_true(is.na(tail(b_rows$time, 1)))
})

