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

# dat1
dat <- array(1:20, dim = c(2, 10))
thres <- 10
dat1 <- array(1:20, dim = c(time = 2, lat = 10))
thres1 <- array(1:2, dim = c(time = 2))
dat1_2 <- array(1:40, c(x = 2, time = 20))
threshold1_2 <- array(rep(10, 20), dim = c(member = 1, time = 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. Sanity checks", {
  # data
  expect_error(
    TotalSpellTimeExceedingThreshold(NULL), 
    "Parameter 'data' cannot be NULL."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold('x'),
    "Parameter 'data' must be numeric."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(array(dat1, dim = c(2, 10)), 10),
    "Parameter 'data' must have named dimensions."
  )
  # time_dim
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, 10, time_dim = 1),
    "Parameter 'time_dim' must be a character string."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(array(dat1, dim = c('sdate' = 20)), 10),
    "Parameter 'time_dim' is not found in 'data' dimension."
  )
  # op
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, 10, op = 1, time_dim = 'time'),
    "Parameter 'op' must be a character."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, 10, op = 'a', time_dim = 'time'),
    "Parameter 'op' must be a logical operator."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, 10, op = c('=','='), time_dim = 'time'),
    "Parameter 'op' is not an accepted pair of logical operators."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, 10, op = c('=','<','>'), time_dim = 'time'),
    "Parameter 'op' must be a logical operator with length 1 or 2."
  )
  # threshold
  expect_error(
    TotalSpellTimeExceedingThreshold(1:20, NULL),
    "Parameter 'threshold' cannot be NULL."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(1:20, 'x'),
    "Parameter 'threshold' must be numeric."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, 10, op = c("<",">"), spell = 6,time_dim = 'time'),
    "If 'op' is a  pair of logical operators parameter 'threshold' also has to be a pair of values."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, list(1:10,1:20), op = c("<",">"), spell = 6, time_dim = 'time'),
    "The pair of thresholds must have the same length."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, list(array(1:10, c(lat = 2, lon = 5)),array(1:10, c(time = 5, lon = 2))), op = c("<",">"), spell = 6, time_dim = 'time'),
    "The pair of thresholds must have the same dimension names."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, list(array(1:10, c(lat = 2, lon = 5)),array(1:10, c(time = 2, lon = 5))), op = c("<",">"), spell = 6, time_dim = 'time'),
    "The pair of thresholds must have the same dimension names."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, list(array(1:3, c(time = 3)),array(1:3, c(time = 3))), op = c("<",">"), spell = 6, time_dim = 'time'),
    "Parameter 'data' and 'threshold' must have same length of all common dimensions."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, 1:10, spell = 6, op = "<", time_dim = 'time'),
    "If parameter 'threshold' is a vector it must have the same length as data time dimension."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, array(rnorm(10)), spell = 6, op = "<", time_dim = 'time'),
    "If parameter 'threshold' is an array it must have named dimensions."
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, array(3, dim = c(time = 3)), op = "<", spell = 6, time_dim = 'time'),
    "Parameter 'data' and 'threshold' must have same length of all common dimensions."
  )
  # spell
  expect_error(
    TotalSpellTimeExceedingThreshold(1:20, thres),
    paste("argument", '"spell"', "is missing, with no default")
  )
  expect_error(
    TotalSpellTimeExceedingThreshold(1:20, thres, spell = 1:2),
    "Parameter 'spell' must be a scalar."
  )
  # ncores
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, 10, time_dim = 'time', spell = 6, ncores = 1.5),
    "Parameter 'ncores' must be a positive integer."
  )
  # dates
  expect_error(
    TotalSpellTimeExceedingThreshold(dat1, 10, op = "<", dates = 2, spell = 6, start = 'a', end = 'b', time_dim = 'time'),
    paste0("Parameter 'start' and 'end' must be lists indicating the ",
           "day and the month of the period start and end.")
  )
  # start and end when dates is not provided
  expect_warning(
    TotalSpellTimeExceedingThreshold(array(1:10, c(time = 10)), threshold = 5, spell = 2, 
                                     start = list(05, 02), end = list(05, 09)),
    paste0("Parameter 'dates' is NULL and the average of the full data ", 
           "provided in 'data' is computed.")
  )
})

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

test_that("2. Output checks", {
  expect_equal(
    TotalSpellTimeExceedingThreshold(dat1, thres1, spell = 2, time_dim = 'time'),  
    array(c(0,rep(2,9)), c(lat = 10))
  )    
  expect_equal(
    TotalSpellTimeExceedingThreshold(dat1_2, 10, spell = 2), 
    array(c(15, 15), c(x = 2))
  )
  expect_equal(
    TotalSpellTimeExceedingThreshold(dat1_2,threshold1_2, spell = 2), 
    array(c(15, 15), c(x = 2, member = 1))
  )
  expect_equal(
    TotalSpellTimeExceedingThreshold(dat2_1, thres2_1, spell = 10), 
    array(c(15, 15), c(x = 2))
  )
  expect_equal(
    TotalSpellTimeExceedingThreshold(dat2_1, thres2_1, spell = 2, time_dim = 'x'),
    array(c(rep(0,5), rep(2,15)), c(time = 20))
  )
  # dimensions
  expect_equal(
    dim(TotalSpellTimeExceedingThreshold(dat2_3, thres2_3, spell = 3)),
    c(sdate = 2, lat = 2)
  )
  expect_equal(
    dim(TotalSpellTimeExceedingThreshold(dat2_3, thres2_4, spell = 3)),
    c(sdate = 2, lat = 2)
  )
  expect_equal(
    dim(TotalSpellTimeExceedingThreshold(dat2_4, thres2_4, spell = 3, time_dim = 'time')),
    c(fyear = 3, sdate = 2, lat = 2)
  )
})

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

test_that("3. Output checks", {

  expect_equal(
    dim(TotalSpellTimeExceedingThreshold(dat3_1, c(55,58), spell = 3, c('<', '>'))),
    c(fyear = 3, sdate = 2, lat = 2)
  )
  expect_equal(
    TotalSpellTimeExceedingThreshold(dat3_1, c(30,60), spell = 3, c(">", "<")),
    array(c(rep(0,6),rep(5, 5), 4), dim = c(fyear = 3, sdate = 2, lat = 2))
  )
  expect_equal(
    TotalSpellTimeExceedingThreshold(dat3_1, c(55,58), spell = 3, c(">=", "<=")),
    array(c(rep(0,11),3), dim = c(fyear = 3, sdate = 2, lat = 2))
  )
  expect_equal(
    TotalSpellTimeExceedingThreshold(dat3_2, c(46, 35), spell = 3, op = c("<", ">"), time_dim = 'time'), 
    array(c(0, 3), c(x = 2))
  )
  expect_equal(
    TotalSpellTimeExceedingThreshold(dat3_2, c(7,11), spell = 3, op = c('>=', '<='), time_dim = 'time'), 
    array(c(3, 0), c(x = 2))
  )
  expect_equal(
    dim(TotalSpellTimeExceedingThreshold(dat2_3, list(thres2_4, thres2_4+1), spell = 3, op = c('>=', '<'))),
    c(sdate = 2, lat = 2)
  )

})

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

test_that("4. Output checks", {

  expect_equal(
    dim(TotalSpellTimeExceedingThreshold(dat4, list(thres4_2, thres4_1), spell = 3, c('<=', '>'))),
    c(fyear = 3, sdate = 2, lat = 2)
  )
  expect_equal(
    as.vector(TotalSpellTimeExceedingThreshold(dat4, list(thres4_1, thres4_2), spell = 3, c(">", "<="))[1:3]),
    c(3, 5, 0)
  )
  expect_equal(
    as.vector(TotalSpellTimeExceedingThreshold(dat4, list(thres4_3, thres4_4), spell = 4, c(">", "<="), time_dim = 'time'))[1:5],
    c(0, 5, 0, 5, 5)
  )
  expect_equal(
    as.vector(TotalSpellTimeExceedingThreshold(dat4, list(thres4_6, thres4_5), spell = 3, op = c("<", ">="), time_dim = 'time'))[1:5], 
    c(3, 5, 0, 5, 3)
  )
  expect_equal(
    as.vector(TotalSpellTimeExceedingThreshold(dat4, list(thres4_7, thres4_8), spell = 3, op = c('>=', '<='), time_dim = 'time'))[4:10], 
    c(5, 3, 5, 4, 3, 5, 5)
  )

})

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

test_that("5. Seasonal Forecasts", {
  exp <- CSTools::lonlat_temp$exp
  exp$data <- exp$data[1,1:3,1:3,,,]
  res <- CST_TotalSpellTimeExceedingThreshold(exp, threshold = 260, spell = 2, time_dim = 'ftime')
  expect_equal(
    res$data[,,1,1],
    array(c(3,3,3,3,3,3,3,3,3), c(member = 3, sdate = 3))
  )
  # compare with percentile
  thresholdP <- Threshold(exp$data, threshold = 0.9)
  WSDI <- CST_TotalSpellTimeExceedingThreshold(exp, threshold = thresholdP, spell = 2, time_dim = 'ftime')
  expect_equal(
    WSDI$data[3,3,3,],
    c(rep(0, 6), rep(2, 2), 0, 2, 0, 2, rep(0, 29), 2, rep(0, 11))
  )
  thresholdP1 <- thresholdP[1,,]
  WSDI1 <- CST_TotalSpellTimeExceedingThreshold(exp, threshold = thresholdP1, spell = 2, time_dim = 'ftime')
  expect_equal(
    WSDI1$data[3,3,3,],
    c(rep(0, 53)))
})

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

test_that("6. Subset Dates and check time_bounds", {
  exp <- CSTools::lonlat_prec
  res <- CST_PeriodMean(data = CSTools::lonlat_prec, 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
  )
})