##############################################################################################
#' @title Compute combined and expanded (95% confidence) temporally aggregated L1 uncertainty
#' due to natural variation, calibration (constant value), and resistance-based FDAS measurement

#' @author
#' Mija Choi \email{choim@battelleecology.org}

#' @description
#' Wrapper function. Compute the combined and expanded (95% confidence) temporally aggregated L1
#' uncertainty for a set of values subject to natural variation, calibration uncertainty, and
#' resistance-based FDAS uncertainty. Uncertainty due to  natural variation is estimated from the
#' standard error of the mean. Uncertainty due to calibration is represented by a constant value
#' coefficient provided by CVAL (U_CVALA3). Uncertainty due to resistance-based FDAS measurement
#' is computed from NEONprocIS.stat::def.ucrt.dp01.fdas.

#' @param data Data frame of L0' (calibrated) data. Must contain columns \code{readout_time} (POSIX) and
#' whatever variable is specified in input parameter \code{VarUcrt} (numeric).
#' A single aggregated uncertainty for the selected variable \code{VarUcrt} will be computed over the full timeseries.
#' @param VarUcrt A character string of the target variable (column) in the data frame \code{data} for
#' which uncertainty data will be computed (all other columns will be ignored in this function).
#' @param ucrtCoef A list of uncertainty coefficients, each a list containing at a minimum the list
#' elements: term (name of L0' term for which the coefficient applies - string), start_date (POSIX),
#' end_date(POSIX), Name (of the coefficient - string), and
#' Value (of the coefficient - string or numeric, to be interpreted as numeric).
#' This will be passed into the calibration and FDAS uncertainty functions. Calibration uncertainty
#' requires the U_CVALA3 coefficient. Resistance-based FDAS uncertainty requires U_CVALR3 and U_CVALR4
#' coefficients.
#' @param ucrtData A data frame of L0' individual measurement uncertainty data generated by the
#' calibration step. This will be passed into the FDAS uncertainty function NEONprocIS.stat::def.ucrt.dp01.fdas.
#' See that function's inputs for required columns.
#' @param log A logger object as produced by NEONprocIS.base::def.log.init to produce structured log
#' output. Defaults to NULL, in which the logger will be created and used within the function.

#' @return A single numeric value representing the aggregated L1 calibration uncertainty over the full record.
#' Numeric NA is returned if no applicable coefficient is found, with warning.

#' @references
#' License: (example) GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
#' NEON.DOC.000785 TIS Level 1 Data products Uncertainty Budget Estimation Plan
#' NEON.DOC.000746 Calibration Fixture and Sensor Uncertainty Analysis: CVAL 2014 Uncertainty Manual

#' @keywords calibration, uncertainty, fdas L1, average

#' @examples
#' data <- data.frame(readout_time=as.POSIXct(c('2019-01-01 00:00','2019-01-01 00:01','2019-01-01 00:02'),tz='GMT'),
#'                    temp=c(.599,.598,.597))
#' ucrtCoef <- list(list(term='temp',start_date=as.POSIXct('2019-01-01',tz='GMT'),end_date=as.POSIXct('2019-01-02',tz='GMT'),Name='U_CVALA3',Value='0.0141'),
#'                  list(term='temp',start_date=as.POSIXct('2019-01-01',tz='GMT'),end_date=as.POSIXct('2019-01-02',tz='GMT'),Name='U_CVALR3',Value='0.000195'),
#'                  list(term='temp',start_date=as.POSIXct('2019-01-01',tz='GMT'),end_date=as.POSIXct('2019-01-02',tz='GMT'),Name='U_CVALR4',Value='0.0067'))
#' ucrtData <- data.frame(readout_time=as.POSIXct(c('2019-01-01 00:00','2019-01-01 00:01','2019-01-01 00:02'),tz='GMT'),
#'                        temp_raw=c(100.187,100.195,100.203),
#'                        temp_dervCal=c(2.5483,2.5481,2.5484),
#'                        temp_ucrtComb=c(0.06861,0.06860,0.06863),
#'                        stringsAsFactors=FALSE)
#' ucrt <- NEONprocIS.stat::wrap.ucrt.dp01.cal.cnst.fdas.rstc(data=data,VarUcrt='temp',ucrtCoef=ucrtCoef,ucrtData=ucrtData)

#' @seealso \link[NEONprocIS.stat]{wrap.ucrt.dp01}
#' @seealso \link[NEONprocIS.stat]{def.ucrt.dp01.cal.cnst}
#' @seealso \link[NEONprocIS.stat]{def.ucrt.dp01.fdas}
#'
# changelog and author contributions / copyrights
#   Mija Choi (2020-12-02)
#     Original Creation
##############################################################################################
# Define test context
context("\n                       Unit test of wrap.ucrt.dp01.cal.cnst.fdas.rstc.R\n")

# Unit test of wrap.ucrt.dp01.cal.cnst.fdas.rstc.R
test_that("Unit test of wrap.ucrt.dp01.cal.cnst.fdas.rstc.R", {
  data <- data.frame(readout_time = as.POSIXct(
    c('2019-01-01 00:00', '2019-01-01 00:01', '2019-01-01 00:02'),
    tz = 'GMT'
  ),
  temp = c(.599, .598, .597))
  
  ucrtCoef <- list(
    list(
      term = 'temp',
      start_date = as.POSIXct('2019-01-01', tz = 'GMT'),
      end_date = as.POSIXct('2019-01-02', tz = 'GMT'),
      Name = 'U_CVALA3',
      Value = '0.0141'
    ),
    list(
      term = 'temp',
      start_date = as.POSIXct('2019-01-01', tz = 'GMT'),
      end_date = as.POSIXct('2019-01-02', tz = 'GMT'),
      Name = 'U_CVALR3',
      Value = '0.000195'
    ),
    list(
      term = 'temp',
      start_date = as.POSIXct('2019-01-01', tz = 'GMT'),
      end_date = as.POSIXct('2019-01-02', tz = 'GMT'),
      Name = 'U_CVALR4',
      Value = '0.0067'
    )
  )
  ucrtData <- data.frame(
    readout_time = as.POSIXct(
      c('2019-01-01 00:00', '2019-01-01 00:01', '2019-01-01 00:02'),
      tz = 'GMT'
    ),
    temp_raw = c(100.187, 100.195, 100.203),
    temp_dervCal = c(2.5483, 2.5481, 2.5484),
    temp_ucrtComb = c(0.06861, 0.06860, 0.06863),
    stringsAsFactors = FALSE
  )
  
  # Happy Path 1 - All params passed
  
  ucrt_returned <- NEONprocIS.stat::wrap.ucrt.dp01.cal.cnst.fdas.rstc(
      data = data,
      VarUcrt = 'temp',
      ucrtCoef = ucrtCoef,
      ucrtData = ucrtData
    )
  
  testthat::expect_true(!is.na(ucrt_returned))
  
  # Sad Path 1 - - column readout_time missing
  
  data_oneLessCol <- subset(data, select = -readout_time)
  
  ucrt_returned <- try(NEONprocIS.stat::wrap.ucrt.dp01.cal.cnst.fdas.rstc(
      data = data_oneLessCol,
      VarUcrt = 'temp',
      ucrtCoef = ucrtCoef,
      ucrtData = ucrtData
    ),silent = TRUE)
  
  testthat::expect_true(class(ucrt_returned)[1] == "try-error")
  
  # Sad Path 2 - data input is not numeric
  
  data_notNumeric <- data
  data_notNumeric$temp <- as.character(data_notNumeric$temp)
  
  ucrt_returned <- try(NEONprocIS.stat::wrap.ucrt.dp01.cal.cnst.fdas.rstc(
      data = data_notNumeric,
      VarUcrt = 'temp',
      ucrtCoef = ucrtCoef,
      ucrtData = ucrtData
    ),silent = TRUE)
  
  testthat::expect_true(class(ucrt_returned)[1] == "try-error")
  
  # Sad Path 3 - When all parameters are NULL, returns NA
  
  data_empty <- c()
  ucrt_returned <- try(NEONprocIS.stat::wrap.ucrt.dp01.cal.cnst.fdas.rstc(
    data = data_empty,
    VarUcrt = 'temp',
    ucrtCoef = NULL,
    ucrtData = NULL
  ), silent = TRUE)
  testthat::expect_true(class(ucrt_returned)[1] == "try-error")
})
