# Test randomizations
context('test randomizations')

library(spatsoc)

DT <- fread('../testdata/DT.csv')

DT[, datetime := as.POSIXct(datetime)]
DT[, yr := year(datetime)]

group_times(DT, datetime = 'datetime', threshold = '1 hour')
group_pts(
  DT,
  threshold = 100,
  id = 'ID',
  timegroup = 'timegroup',
  coords = c('X', 'Y')
)

test_that('DT, type, id, datetime, (group) are required', {
  expect_error(randomizations(DT = NULL),
               'DT must be provided')

  expect_error(randomizations(DT = DT,
                              type = NULL),
               'type must be', fixed = FALSE)

  expect_error(randomizations(DT = DT,
                              type = 'step',
                              id = NULL),
               'id must be provided')

  expect_error(randomizations(DT = DT,
                              type = 'step',
                              id = 'ID',
                              datetime = NULL),
               'datetime must be')

  # Group required for daily and step
  expect_error(randomizations(DT = DT,
                              type = 'step',
                              id = 'ID',
                              iterations = 1,
                              group = NULL,
                              datetime = 'timegroup'),
               'group must be provided if type is "step" or "daily"')

  expect_error(randomizations(DT = DT,
                              type = 'daily',
                              id = 'ID',
                              group = NULL,
                              iterations = 1,
                              datetime = 'datetime'),
               'group must be provided if type is "step" or "daily"')

})

test_that('type must be one of options', {
  expect_error(randomizations(DT = DT,
                              type = 'potato'),
               'type of randomization must be one of', fixed = FALSE)
})

test_that('fields provided must be in DT', {
  expect_error(randomizations(DT = DT,
                              type = 'step',
                              id = 'potato',
                              datetime = 'datetime'),
               'potato field', fixed = TRUE)

  expect_error(randomizations(DT = DT,
                              type = 'step',
                              id = 'ID',
                              datetime = 'potato'),
               'potato field', fixed = TRUE)

  expect_error(randomizations(DT = DT,
                              type = 'step',
                              id = 'ID',
                              datetime = 'datetime',
                              splitBy = 'potato'),
               'potato field', fixed = TRUE)
})

test_that('iterations is NULL or correctly provided', {
  copyDT <- copy(DT)
  expect_warning(randomizations(DT = copyDT,
                              type = 'step',
                              id = 'ID',
                              group = 'group',
                              datetime = 'datetime',
                              iterations = NULL),
               'iterations is not provided', fixed = FALSE)

  expect_error(randomizations(DT = DT,
                              type = 'step',
                              id = 'ID',
                              datetime = 'datetime',
                              iterations = 'potato'),
               'iterations must be of class', fixed = FALSE)
})

test_that('dateFormatted or not depending on randomization type', {
  expect_warning(randomizations(DT = DT,
                                type = 'step',
                                id = 'ID',
                                group = 'group',
                                datetime = 'datetime',
                                iterations = 1),
                 'datetime provided is POSIXct', fixed = FALSE)

  DT[, numDate := 1]
  expect_error(randomizations(DT = DT,
                              type = 'daily',
                              id = 'ID',
                              group = 'group',
                              datetime = 'numDate',
                              iterations = 3),
                 'datetime must be POSIXct', fixed = FALSE)

  expect_error(randomizations(DT = DT,
                              type = 'trajectory',
                              id = 'ID',
                              coords = c('X', 'Y'),
                              datetime = 'numDate',
                              iterations = 3),
                 'datetime must be POSIXct', fixed = FALSE)
})


test_that('step randomization returns as expected', {
  # N unique randomIDs same as N unique IDs in each timegroup
  expect_equal(
    randomizations(
      DT = DT,
      type = 'step',
      id = 'ID',
      group = 'group',
      iterations = 1,
      datetime = 'timegroup'
    )[, uniqueN(randomID), by = timegroup],
    DT[, uniqueN(ID), by = timegroup])

  # N rows in output is (nrows * iterations + 1)
  expect_equal(nrow(
    randomizations(
      DT = DT,
      type = 'step',
      id = 'ID',
      group = 'group',
      iterations = 3,
      datetime = 'timegroup'
    )
  ),
  nrow(DT) * (3 + 1))

  copyDT <- copy(DT)[, population := 1][1:50, population := 2]
  expect_equal(
    randomizations(
      DT = copyDT,
      type = 'step',
      id = 'ID',
      group = 'group',
      iterations = 1,
      datetime = 'timegroup',
      splitBy = 'population'
    )[, uniqueN(randomID), by = timegroup],
    copyDT[, uniqueN(ID), by = timegroup])
})


test_that('daily randomization returns as expected', {
  expect_equal(
    randomizations(
      DT = DT,
      type = 'daily',
      id = 'ID',
      group = 'group',
      iterations = 1,
      datetime = 'datetime'
    )[, .(N = uniqueN(randomID)),
      by = .(jul, ID, iteration)][, max(N)],
    1)
})

test_that('trajectory randomization returns as expected', {
  expect_equal(
    randomizations(
      DT = DT,
      type = 'trajectory',
      id = 'ID',
      coords = c('X', 'Y'),
      iterations = 1,
      datetime = 'datetime'
    )[, uniqueN(randomJul), by = .(ID, jul, iteration)][, max(V1)],
    1)


  expect_equal(
    nrow(randomizations(
      DT = DT,
      type = 'trajectory',
      coords = c('X', 'Y'),
      id = 'ID',
      iterations = 3,
      datetime = 'datetime'
    )),
    nrow(DT) * (3 + 1))

  expect_true(all(c('X', 'Y', 'randomdatetime') %in%
                    colnames(
                      randomizations(
                        DT = DT,
                        type = 'trajectory',
                        coords = c('X', 'Y'),
                        id = 'ID',
                        iterations = 3,
                        datetime = 'datetime'
                      )
                    )))

})

test_that('non uniques are found', {
  copyDT <- copy(DT)
  copyDT[2, (colnames(DT)) := copyDT[1, .SD]]

  expect_warning(randomizations(DT = copyDT,
                                type = 'daily',
                                id = 'ID',
                                group = 'group',
                                datetime = 'datetime',
                                iterations = 2),
                 'found non-unique rows of id, datetime',
                 fixed = FALSE)
})

test_that('randomization returns expected columns', {
  expect_true(all(c('observed', 'iteration')
                  %in% colnames(
    randomizations(
      DT = DT,
      type = 'daily',
      id = 'ID',
      group = 'group',
      datetime = 'datetime',
      iterations = 2
    )
  )))

  # if step, randomID
  expect_true('randomID' %in% colnames(
    randomizations(
      DT = DT,
      type = 'step',
      id = 'ID',
      group = 'group',
      datetime = 'timegroup',
      iterations = 2
    )
  ))

  # if daily, randomID and jul
  expect_true(all(c('randomID', 'jul') %in% colnames(
    randomizations(
      DT = DT,
      type = 'daily',
      id = 'ID',
      group = 'group',
      datetime = 'datetime',
      iterations = 2
    )
  )))

  # if trajectory, randomJul and randomdatetime and jul
  expect_true('randomJul' %in% colnames(
    randomizations(
      DT = DT,
      type = 'trajectory',
      id = 'ID',
      coords = c('X', 'Y'),
      datetime = 'datetime',
      iterations = 2
    )
  ))

  expect_true('randomdatetime' %in% colnames(
    randomizations(
      DT = DT,
      type = 'trajectory',
      id = 'ID',
      coords = c('X', 'Y'),
      datetime = 'datetime',
      iterations = 2
    )
  ))

  expect_error(
    randomizations(
      DT = DT,
      type = 'trajectory',
      id = 'ID',
      coords = NULL,
      datetime = 'datetime',
      iterations = 2),
      'coords must be provided if type is "trajectory"'
    )
})





test_that('randomization is silent when an individual only has one row', {
  ## Fixed here: 6092ad8d055ff269d39dd481a80f27069c790630

  # ** Fake an individual with 1 relocation**
  copyDT <- copy(DT)[1, ID := 'Z']

  # Temporal grouping
  group_times(copyDT, datetime = 'datetime', threshold = '5 minutes')

  # Spatial grouping with timegroup
  group_pts(
    copyDT,
    threshold = 5,
    id = 'ID',
    coords = c('X', 'Y'),
    timegroup = 'timegroup'
  )

  expect_s3_class(randomizations(
    copyDT,
    type = 'step',
    id = 'ID',
    group = 'group',
    datetime = 'timegroup',
    splitBy = 'yr',
    iterations = 2
  ), 'data.table')


  expect_s3_class(  randomizations(
    copyDT,
    type = 'daily',
    id = 'ID',
    group = 'group',
    datetime = 'datetime',
    splitBy = 'yr',
    iterations = 2
  ), 'data.table')


  expect_s3_class(  randomizations(
    copyDT,
    type = 'trajectory',
    id = 'ID',
    group = NULL,
    coords = c('X', 'Y'),
    datetime = 'datetime',
    splitBy = 'yr',
    iterations = 2
  ), 'data.table')


})



test_that('n individuals consistent across years', {
  DT[1, ID := 'Z']

  ## Step
  randStep <- randomizations(
    DT,
    type = 'step',
    id = 'ID',
    group = 'group',
    splitBy = 'yr',
    datetime = 'timegroup',
    iterations = 20
  )

  uID <- randStep[, .(nID = .N), by = .(randomID, yr, iteration)]

  expect_equal(
    uID[, sd(nID), by = .(randomID, yr)]$V1,
    rep(0, randStep[, uniqueN(randomID)])
  )

  ## Daily
  randDaily <- randomizations(
    DT,
    type = 'daily',
    id = 'ID',
    group = 'group',
    splitBy = 'yr',
    datetime = 'datetime',
    iterations = 20
  )
  uJul <- randDaily[, .(nDay = uniqueN(jul)), by = .(randomID, yr, iteration)]

  expect_equal(
    uJul[, sd(nDay), by = .(randomID, yr)]$V1,
    rep(0, nrow(randDaily[, .N, .(randomID, yr)]))
  )

})
