#' Group mean direction
#'
#' `direction_group` calculates the mean direction of all individuals in each
#' spatiotemporal group identified by [group_pts()]. The function expects a
#' `data.table` with relocation data appended with a `direction` column from
#' [direction_step()] and a `group` column from [group_pts()].
#'
#' The `DT` must be a `data.table`. If your data is a `data.frame`, you can
#' convert it by reference using [data.table::setDT()] or by reassigning using
#' [data.table::data.table()].
#'
#' The `direction` and `group` arguments expect the names of columns in `DT`
#' which correspond to the direction and group columns. The direction column is
#' expected in units of radians and the mean calculated with
#' [CircStats::circ.mean()].
#'
#' @param DT input data.table with direction column generated by
#'   [direction_step()] and group column generated with [group_pts()]
#' @param direction character string of direction column name, default
#'   "direction", expects that the unit of the direction column is radians.
#' @param group character string of group column name, default "group"
#'
#' @return `direction_group` returns the input `DT` appended with a
#'   `group_direction` column representing the mean direction of all individuals
#'   in each spatiotemporal group.
#'
#'   The mean direction is calculated using [CircStats::circ.mean()] which
#'   expects units of radians.
#'
#'   A message is returned when the `group_direction` columns already exists in
#'   the input `DT`, because it will be overwritten.
#'
#'   See details for appending outputs using modify-by-reference in the
#'   [FAQ](https://docs.ropensci.org/spatsoc/articles/faq.html).
#'
#' @export
#' @seealso [direction_step()], [group_pts()],
#'   [CircStats::circ.mean()]
#' @family Direction functions
#'
#' @references
#' See examples of using mean group direction:
#'  * \doi{doi:10.1098/rsos.170148}
#'  * \doi{doi:10.1098/rsos.201128}
#'  * \doi{doi:10.1016/j.beproc.2018.01.013}
#'
#' @examples
#' # Load data.table
#' library(data.table)
#' \dontshow{data.table::setDTthreads(1)}
#'
#' # Read example data
#' DT <- fread(system.file("extdata", "DT.csv", package = "spatsoc"))
#'
#' # Cast the character column to POSIXct
#' DT[, datetime := as.POSIXct(datetime, tz = 'UTC')]
#'
#' # Temporal grouping
#' group_times(DT, datetime = 'datetime', threshold = '20 minutes')
#'
#' # Spatial grouping with timegroup
#' group_pts(DT, threshold = 50, id = 'ID',
#'           coords = c('X', 'Y'), timegroup = 'timegroup')
#'
#' # Calculate direction at each step
#' direction_step(
#'   DT = DT,
#'   id = 'ID',
#'   coords = c('X', 'Y'),
#'   crs = 32736
#' )
#'
#' # Calculate group direction
#' direction_group(DT)
#'
#' # Or, using the new geometry interface
#' get_geometry(DT, coords = c('X', 'Y'), crs = 32736)
#' group_pts(DT, threshold = 5, id = 'ID', timegroup = 'timegroup')
#' direction_step(DT, id = 'ID')
#' direction_group(DT)
direction_group <- function(
    DT,
    direction = 'direction',
    group = 'group') {
  # due to NSE notes in R CMD check
  dir <- out <- NULL

  assert_not_null(DT)
  assert_is_data_table(DT)

  assert_not_null(direction)
  assert_not_null(group)
  assert_are_colnames(DT, c(direction, group))

  assert_col_inherits(DT, direction, 'units')
  assert_col_radians(DT, direction, ', did you use direction_step?')

  out_mean <- 'group_direction'
  if (out_mean %in% colnames(DT)) {
    message(paste(out_mean, 'column will be overwritten by this function'))
    data.table::set(DT, j = out_mean, value = NULL)
  }

  DT[, out := CircStats::circ.mean(as.numeric(dir)),
    by = c(group),
    env = list(dir = direction, out = out_mean)]

  DT[, out := units::as_units(out, 'rad'), env = list(out = out_mean)]

  return(DT[])
}

