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

# cube1
dims <- c(syear = 6, time = 3, latitude = 2, ensemble = 25)
cube1 <- NULL
cube1$data <- array(rnorm(600, -204.1, 78.1), dim = dims)
class(cube1) <- 's2dv_cube'

# dat1
dims <- c(syear = 6, time = 2, latitude = 2, ensemble = 25)
dimscor <- c(syear = 1, time = 2, latitude = 2, ensemble = 25)
dimscor1_1 <- c(syear = 1, time = 3, latitude = 2, ensemble = 25)
set.seed(1)
dat1 <- array(rnorm(600, -194.5, 64.8), dim = dims)
set.seed(2)
datcor1 <- array(rnorm(100, -217.8, 68.29), dim = dimscor)
set.seed(3)
datcor1_1 <- array(rnorm(100, -217.8, 68.29), dim = dimscor1_1)

# dates1
dates1 <- as.Date(c(paste0(2010:2015, "-08-16"), paste0(2010:2015, "-09-15"), 
                    paste0(2010:2015, "-10-16")))
dim(dates1) <- c(syear = 6, time = 3)

# dat2
dims2 <- c(styear = 6, ftime = 2, lat = 2, member = 25)
dimscor2_1 <- c(syear = 1, ftime = 2, lat = 2, ensemble = 25)
dimscor2_2 <- c(styear = 1, ftime = 2, lat = 2, ensemble = 25)
set.seed(1)
dat2 <- array(rnorm(600, -194.5, 64.8), dim = dims2)
set.seed(2)
datcor2_1 <- array(rnorm(100, -194.5, 64.8), dim = dimscor2_1)
set.seed(2)
datcor2_2 <- array(rnorm(100, -194.5, 64.8), dim = dimscor2_2)

# dat3
dims3 <- c(syear = 6, time = 2, lat = 2, ensemble = 25)
set.seed(1)
dat3 <- array(abs(rnorm(600, 21.19, 25.64)), dim = dims)


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

test_that("1. Initial checks CST_PeriodStandardization", {
  # Check 's2dv_cube'
  expect_error(
    CST_PeriodStandardization(data = NULL), 
    "Parameter 'data' cannot be NULL."
  )
  expect_error(
    CST_PeriodStandardization(data = array(10)), 
    "Parameter 'data' must be of 's2dv_cube' class."
  )
})

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

test_that("1. Initial checks PeriodStandardization", {
  # data
  expect_error(
    PeriodStandardization(data = NULL), 
    "Parameter 'data' must be a numeric array."
  )
  expect_error(
    PeriodStandardization(data = array(1)), 
    "Parameter 'data' must have dimension names."
  )
  # data_cor
  expect_error(
    PeriodStandardization(data = dat1, data_cor = 1), 
    "Parameter 'data_cor' must be a numeric array."
  )
  expect_error(
    PeriodStandardization(data = dat1, data_cor = array(1:2)), 
    "Parameter 'data_cor' must have dimension names."
  )
  # time_dim
  expect_error(
    PeriodStandardization(data = dat1, time_dim = 1),
    "Parameter 'time_dim' must be a character string."
  )
  expect_error(
    PeriodStandardization(data = dat2),
    "Parameter 'time_dim' is not found in 'data' dimension."
  )
  expect_error(
    PeriodStandardization(data = dat2, data_cor = dat1, time_dim = 'ftime'),
    "Parameter 'time_dim' is not found in 'data_cor' dimension."
  )
  # leadtime_dim
  expect_error(
    PeriodStandardization(data = dat1, leadtime_dim = 1),
    "Parameter 'leadtime_dim' must be a character string."
  )
  expect_error(
    PeriodStandardization(data = dat2, time_dim = 'ftime'),
    "Parameter 'leadtime_dim' is not found in 'data' dimension."
  )
  expect_error(
    PeriodStandardization(data = dat2, data_cor = datcor2_1, time_dim = 'ftime',
                          leadtime_dim = 'styear'),
    "Parameter 'leadtime_dim' is not found in 'data_cor' dimension."
  )
  # memb_dim
  expect_error(
    PeriodStandardization(data = dat1, memb_dim = 1),
    "Parameter 'memb_dim' must be a character string."
  )
  expect_error(
    PeriodStandardization(data = dat2, time_dim = 'styear', leadtime_dim = 'ftime'),
    "Parameter 'memb_dim' is not found in 'data' dimension."
  )
  expect_error(
    PeriodStandardization(data = dat2, data_cor = datcor2_2, time_dim = 'styear', 
                          leadtime_dim = 'ftime', memb_dim = 'member'),
    "Parameter 'memb_dim' is not found in 'data_cor' dimension."
  )
  # data_cor (2)
  expect_error(
    PeriodStandardization(data = dat1, data_cor = datcor1_1),
    paste0("Parameter 'data' and 'data_cor' have dimension 'leadtime_dim' ", 
           "of different length.")
  )
  # ref_period
  expect_warning(
    PeriodStandardization(data = dat1, ref_period = list(1,2)),
    paste0("Parameter 'dates' is not provided so 'ref_period' can't be ", 
           "used.")
  )
  expect_warning(
    PeriodStandardization(data = dat1, ref_period = list(2020, 2021), 
                          dates = dates1),
    paste0("Parameter 'ref_period' contains years outside the dates. ", 
           "It will not be used.")
  )
  # handle_infinity
  # method
  # distribution
  # na.rm
  expect_error(
    PeriodStandardization(data = dat1, na.rm = 1.5),
    "Parameter 'na.rm' must be logical."
  )
  # ncores
  expect_error(
    PeriodStandardization(data = dat1, ncores = 1.5),
    "Parameter 'ncores' must be a positive integer."
  ) 
})

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

test_that("2. Output checks", {
  # CST_PeriodStandardization
  SPEI_s2dv_cube <- CST_PeriodStandardization(data = cube1)
  expect_equal(
    names(SPEI_s2dv_cube),
    c('data', 'attrs')
  )
  # PeriodStandardization
  SPEI <- PeriodStandardization(data = dat1)
  expect_equal(
    dim(SPEI),
    c(syear = 6, time = 2, latitude = 2, ensemble = 25)
  )
  expect_equal(
    SPEI[,1,1,1],
    c(-0.4842599, 0.4072574, -0.8119087, 1.5490196, 0.5467044, -0.7719460),
    tolerance = 0.0001
  )
  SPEIcor <- PeriodStandardization(data = dat1, data_cor = datcor1)
  expect_equal(
    dim(SPEIcor),
    c(syear = 1, time = 2, latitude = 2, ensemble = 25)
  )
  expect_equal(
    SPEIcor[,,1,1],
    c(-1.232981, -0.309125),
    tolerance = 0.0001
  )
  # time_dim, leadtime_dim, memb_dim
  expect_equal(
    PeriodStandardization(data = dat2, time_dim = 'ftime', 
                          leadtime_dim = 'styear', memb_dim = 'member')[1:4],
    c(-0.8229475, 0.1918119, -0.7627081, 0.9955730),
    tolerance = 0.0001
  )
  # ref_period
  dates <- dates1
  ref_period = list(2011, 2014)
  # handle_infinity
  expect_equal(
    any(is.infinite(PeriodStandardization(data = dat1, handle_infinity = T))),
    FALSE
  )
  # method
  expect_equal(
    PeriodStandardization(data = dat1, method = 'non-parametric')[,1,1,1],
    c(-0.5143875, 0.3492719, -0.7163839, 1.6413758, 0.4580046, -0.6949654),
    tolerance = 0.0001
  )
  # distribution
  expect_equal(
    all(is.na(PeriodStandardization(data = dat1, distribution = 'Gamma'))),
    TRUE
  )
  expect_equal(
    PeriodStandardization(data = dat3, distribution = 'Gamma')[1:5],
    c(-1.2059075, 0.3285372, -3.1558450, 1.5034088, 0.5123442)
  )
  # na.rm
  dat1[1,1,1,1] <- NA
  expect_equal(
    all(is.na(PeriodStandardization(data = dat1, na.rm = FALSE)[,1,1,1])),
    TRUE
  )
  expect_equal(
    !all(is.na(PeriodStandardization(data = dat1, na.rm = TRUE)[,1,1,1])),
    TRUE
  )
  expect_equal(
    any(is.na(PeriodStandardization(data = dat1, data_cor = datcor1, na.rm = TRUE))),
    FALSE
  )
  expect_equal(
    any(is.na(PeriodStandardization(data = dat1, data_cor = datcor1, na.rm = FALSE))),
    TRUE
  )
  # ncores
})
