##############################################

library(CSTools)

# dat1
dat1 <- 1:20

# dat2
dat2_1 <- array(1:40, c(x = 2, time = 20))
thres2_1 <- array(10, dim = c(member = 1, time = 1))
dat2_3 <- array(1:20, c(time = 5, sdate = 2, lat = 2))
thres2_3 <- array(1:5, c(time = 5))
dat2_4 <- array(1:60, c(time = 5, fyear = 3, sdate = 2, lat = 2))
thres2_4 <- array(1:2, c(lat = 2))

# dat3
dat3_1 <- array(1:60, c(time = 5, fyear = 3, sdate = 2, lat = 2))
dat3_2 <- array(1:40, c(x = 2, time = 20))

# dat4
set.seed(1)
dat4 <- array(rnorm(60, 23), c(time = 5, fyear = 3, sdate = 2, lat = 2))
set.seed(1)
thres4_1 <- array(rnorm(20, 20), c(time = 5, sdate = 2, lat = 2))
set.seed(2)
thres4_2 <- array(rnorm(20, 25), c(time = 5, sdate = 2, lat = 2))
set.seed(1)
thres4_3 <- array(rnorm(20, 20), c(time = 5, sdate = 2))
set.seed(2)
thres4_4 <- array(rnorm(20, 25), c(time = 5, sdate = 2))
set.seed(1)
thres4_5 <- array(rnorm(5, 20), c(time = 5))
set.seed(2)
thres4_6 <- array(rnorm(5, 25), c(time = 5))
set.seed(1)
thres4_7 <- rnorm(5, 20)
set.seed(2)
thres4_8 <- rnorm(5, 25)

##############################################
test_that("1. Input checks", {
  # data
  expect_error(
    AccumulationExceedingThreshold(NULL), 
    "Parameter 'data' cannot be NULL."
  )
  expect_error(
    AccumulationExceedingThreshold('x'),
   "Parameter 'data' must be numeric."
  )
  expect_error(
    AccumulationExceedingThreshold(array(dat1, dim = c(2, 10)), 10),
    "Parameter 'data' must have named dimensions."
  )
  # time_dim
  expect_error(
    AccumulationExceedingThreshold(dat1, 10, time_dim = 1),
    "Parameter 'time_dim' must be a character string."
  )
  expect_error(
    AccumulationExceedingThreshold(array(dat1, dim = c('sdate' = 20)), 10),
    "Parameter 'time_dim' is not found in 'data' dimension."
  )
  # op
  expect_error(
    AccumulationExceedingThreshold(dat1, 10, op = 1),
    "Parameter 'op' must be a character."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, 10, op = 'a'),
    "Parameter 'op' must be a logical operator."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, 10, op = c('=','=')),
    "Parameter 'op' is not an accepted pair of logical operators."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, 10, op = c('=','<','>')),
    "Parameter 'op' must be a logical operator with length 1 or 2."
  )
  # threshold
  expect_error(
    AccumulationExceedingThreshold(dat1, NULL),
    "Parameter 'threshold' cannot be NULL."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, 'x'),
    "Parameter 'threshold' must be numeric."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, 10, op = c("<",">")),
    "If 'op' is a  pair of logical operators parameter 'threshold' also has to be a pair of values."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, list(1:10,1:20), op = c("<",">")),
    "The pair of thresholds must have the same length."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, list(array(1:10, c(lat = 2, lon = 5)),array(1:10, c(time = 5, lon = 2))), op = c("<",">")),
    "The pair of thresholds must have the same dimension names."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, list(array(1:10, c(lat = 2, lon = 5)),array(1:10, c(time = 2, lon = 5))), op = c("<",">")),
    "The pair of thresholds must have the same dimension names."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, list(array(1:10, c(time = 2)),array(1:10, c(time = 2))), op = c("<",">"), time_dim = 'time'),
    "Parameter 'data' and 'threshold' must have same length of all common dimensions."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, 1:10, op = "<"),
    "If parameter 'threshold' is a vector it must have the same length as data time dimension."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, array(rnorm(10)), op = "<"),
    "If parameter 'threshold' is an array it must have named dimensions."
  )
  expect_error(
    AccumulationExceedingThreshold(dat1, array(20, dim = c(time = 2)), op = "<", time_dim = 'time'),
    "Parameter 'data' and 'threshold' must have same length of all common dimensions."
  )
  # ncores
  expect_error(
    AccumulationExceedingThreshold(dat1, 10, time_dim = 'x', ncores = 1.5),
    "Parameter 'ncores' must be a positive integer."
  )
  # dates
  expect_error(
    AccumulationExceedingThreshold(dat1, 10, op = "<", dates = 2, start = 'a', end = 'b'),
    paste0("Parameter 'start' and 'end' must be lists indicating the ",
           "day and the month of the period start and end.")
  )
  # diff
  expect_error(
    AccumulationExceedingThreshold(dat2_3, thres2_3, diff = T),
    paste0("Parameter 'diff' can't be TRUE if the parameter 'threshold' is not a scalar.")
  )
})

##############################################
test_that("2. Output checks", {
  expect_equal(
    AccumulationExceedingThreshold(dat1, 10),
    155
  )
  expect_equal(
    AccumulationExceedingThreshold(dat2_1, 10, time_dim = 'time'), 
    array(c(375, 390), c(x = 2))
  )
  expect_equal(
    AccumulationExceedingThreshold(dat2_1, thres2_1, time_dim = 'time'), 
    array(c(375, 390), c(x = 2))
  )
  expect_equal(
    AccumulationExceedingThreshold(dat2_1, thres2_1, time_dim = 'x'),
    array(c(rep(0,5), seq(23, 79, 4)), c(time = 20))
  )
  expect_equal(
    AccumulationExceedingThreshold(dat2_1, 10, time_dim = 'time'),
    array(c(375, 390), c(x = 2))
  )
  # dimensions
  expect_equal(
    dim(AccumulationExceedingThreshold(dat2_3, thres2_3)),
    c(sdate = 2, lat = 2)
  )
  expect_equal(
    dim(AccumulationExceedingThreshold(dat2_3, thres2_4)),
    c(sdate = 2, lat = 2)
  )
  expect_equal(
    dim(AccumulationExceedingThreshold(dat2_4, thres2_4, time_dim = 'time')),
    c(fyear = 3, sdate = 2, lat = 2)
  )

})

##############################################
test_that("3. Output checks", {

  expect_equal(
    dim(AccumulationExceedingThreshold(dat3_1, c(55,58), c('<', '>'))),
    c(fyear = 3, sdate = 2, lat = 2)
  )
  expect_equal(
    AccumulationExceedingThreshold(dat3_1, c(55,58), c(">", "<")),
    array(c(rep(0,11),113), dim = c(fyear = 3, sdate = 2, lat = 2))
  )
  expect_equal(
    AccumulationExceedingThreshold(dat3_1, c(55,58), c(">=", "<=")),
    array(c(rep(0,10),55,171), dim = c(fyear = 3, sdate = 2, lat = 2))
  )
  expect_equal(
    AccumulationExceedingThreshold(dat3_2, c(46, 35), op = c("<", ">"), time_dim = 'time'), 
    array(c(76, 114), c(x = 2))
  )
  expect_equal(
    AccumulationExceedingThreshold(dat3_2, c(7,11), op = c('>=', '<='), time_dim = 'time'), 
    array(c(27, 18), c(x = 2))
  )
  expect_equal(
    dim(AccumulationExceedingThreshold(dat2_3, list(thres2_4, thres2_4+1), op = c('>=', '<'))),
    c(sdate = 2, lat = 2)
  )

})

##############################################

test_that("4. Output checks", {

  expect_equal(
    dim(AccumulationExceedingThreshold(dat4, list(thres4_2, thres4_1), c('<=', '>'))),
    c(fyear = 3, sdate = 2, lat = 2)
  )
  expect_equal(
    as.vector(AccumulationExceedingThreshold(dat4, list(thres4_1, thres4_2), c(">", "<="))[1:3]),
    c(91.05107, 115.67568, 69.89353),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AccumulationExceedingThreshold(dat4, list(thres4_3, thres4_4), c(">", "<="), time_dim = 'time'))[1:5],
    c(91.05107, 115.67568, 69.89353, 117.29783, 115.40615),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AccumulationExceedingThreshold(dat4, list(thres4_6, thres4_5), op = c("<", ">="), time_dim = 'time'))[1:5], 
    c(91.05107, 115.67568, 69.89353, 117.29783, 94.39550),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(AccumulationExceedingThreshold(dat4, list(thres4_7, thres4_8), op = c('>=', '<='), time_dim = 'time'))[4:10], 
    c(117.29783, 94.39550, 113.25711, 90.85402, 91.89458, 115.14699, 116.19438),
    tolerance = 0.0001
  )

})

##############################################

test_that("5. Seasonal forecasts", {
  exp <- CSTools::lonlat_temp$exp
  exp$data <- exp$data[ , 1:4, 1:2, , , ]
  res <- CST_AccumulationExceedingThreshold(exp, threshold = 280, time_dim = 'ftime')

  expect_equal(
    round(res$data[, 2, 2, 2]),
    c(0, 280, 281, 281)
  )

  # GDD
  exp <- array(NA, dim = c(member = 6, sdate = 3, time = 214, lat = 4, lon = 4))
  exp1 <- drop(CSTools::lonlat_prec$data) * 86400000
  exp[, , 1:31, , ] <- exp1 + 10; exp[, , 32:62, , ] <- exp1 + 11
  exp[, , 63:93, , ] <- exp1 + 12; exp[, , 94:124, , ] <- exp1 + 13
  exp[, , 125:155, , ] <- exp1 + 14; exp[, , 156:186, , ] <- exp1 + 15
  exp[, , 187:214, , ] <- exp1[, , 1:28, , ] + 16

  Dates <- c(seq(as.Date("01-05-2000", format = "%d-%m-%Y"), 
                 as.Date("30-11-2000", format = "%d-%m-%Y"), by = 'day'),
             seq(as.Date("01-05-2001", format = "%d-%m-%Y"), 
                 as.Date("30-11-2001", format = "%d-%m-%Y"), by = 'day'),
             seq(as.Date("01-05-2002", format = "%d-%m-%Y"), 
                 as.Date("30-11-2002", format = "%d-%m-%Y"), by = 'day'))
  dim(Dates) <- c(sdate = 3, time = 214)
  GDD <- AccumulationExceedingThreshold(exp - 17, threshold = 0, dates = Dates, time_dim = 'time', 
                                        start = list(1, 4), end = list(31, 10), na.rm = TRUE)
  
  expect_equal(
    round(GDD[,1,1,1]),
    c(549, 387, 125, 554, 245, 282)
  )
  expect_equal(
    dim(GDD),
    c(member = 6, sdate = 3, lat = 4, lon = 4)
  )
  expect_error(
    AccumulationExceedingThreshold(exp - 17, threshold = 0, dates = Dates, start = list(1, 4), end = list(31, 10), time_dim = 'ftime'),
    "Parameter 'time_dim' is not found in 'data' dimension."
  )
  expect_equal(
    !any(is.na(AccumulationExceedingThreshold(exp - 17, threshold = 0, dates = Dates, time_dim = 'time',start = list(1, 4), end = list(31, 10)))),
    !any(is.na(c(1, 1)))
  )

  # test the 'diff'
  input_1 <- c(1:20)
  threshold_1 <- 3
  input_2 <- -input_1[1:15]
  threshold_2 <- -5

  expect_equal(
    AccumulationExceedingThreshold(input_1, threshold_1, diff = TRUE),
    153
  )
  expect_equal(
    AccumulationExceedingThreshold(input_1, threshold_1),
    204
  )
  expect_equal(
    AccumulationExceedingThreshold(input_2, threshold_2, op = '<'),
    -105
  )
  expect_equal(
    AccumulationExceedingThreshold(input_2, threshold_2, op = '<', diff = TRUE),
    -55
  )
})

##############################################
test_that("6. Subset Dates and check time_bounds", {
  exp <- CSTools::lonlat_prec
  res <- CST_AccumulationExceedingThreshold(data = exp, threshold = mean(exp$data),
                                            time_dim = 'ftime', start = list(10, 03), 
                                            end = list(20, 03))
  # Check dims
  expect_equal(
    dim(res$data), 
    res$dims
  )
  # Check Dates
  expect_equal(
    dim(res$data)['sdate'], 
    dim(res$attrs$Dates)
  )
  # Check time_bounds
  expect_equal(
    res$attrs$Dates, 
    res$attrs$time_bounds$start
  )
  expect_equal(
    dim(res$attrs$time_bounds$start), 
    dim(res$attrs$time_bounds$end)
  )
  # Check 'sdates'
  expect_equal(
    all(lubridate::month(res$attrs$time_bounds$start) == 3),
    TRUE
  )
  expect_equal(
    all(lubridate::day(res$attrs$time_bounds$start) == 10),
    TRUE
  )
  expect_equal(
    all(lubridate::month(res$attrs$time_bounds$end) == 03),
    TRUE
  )
  expect_equal(
    all(lubridate::day(res$attrs$time_bounds$end) == 20),
    TRUE
  )
})
