context("CSTools::CST_QuantileMapping tests")

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

# dat1
exp1 <- list(data = array(1:20, dim = c(time = 20)))
class(exp1) <- 's2dv_cube'

obs1 <- list(data = array(1:20, dim = c(time = 20)))
class(obs1) <- 's2dv_cube'

exp1_2 <- list(data = array(1:20, dim = c(20)))
class(exp1_2) <- 's2dv_cube'

obs1_2 <- list(data = array(1:20, dim = c(20)))
class(obs1_2) <- 's2dv_cube'

exp_cor1 <- list(data = array(1:20, dim = c(20)))
class(exp_cor1) <- 's2dv_cube'

# dat2
exp2 <- list(data = array(1:20, dim = c(sdate = 5, member = 4)))
class(exp2) <- 's2dv_cube'

obs2 <- list(data = array(1:20, dim = c(sdate = 5, time = 4)))
class(obs2) <- 's2dv_cube'

res2 <- NULL
res2$data <- t(array(c(0, 2:20), c(sdate = 5, member = 4)))
names(dim(res2$data)) <- c('member', 'sdate')
class(res2) <- 's2dv_cube'

# dat3
exp3 <- exp2
obs3 <- obs2
res3 <- res2
exp3$data[1] <- NA
obs3$data[1] <- NA
res3$data[c(1,2),1] <- c(NA,6)
res3$data[1,2] <- 0

res3_1 <- res3
res3_1$data <- array(c(NA, 6, 11, 16, rep(NA, 16)), c(member = 4, sdate = 5))

exp3_2 <- exp3
obs3_2 <- obs3
res3_2 <- res3_1
exp3_2$data[1] <- 1
obs3_2$data[1] <- NA
res3_2$data[1] <- 0

# dat4
lon <- seq(0, 3)
lat <- seq(48, 45)
set.seed(1)
exp4 <- NULL
exp4$data <- array(runif(1152)*280, dim = c(dataset = 1, member = 4, sdate = 6, 
                                            ftime = 3, lat = 4, lon = 4))
exp4$coords <- list(lon = lon, lat = lat)
class(exp4) <- 's2dv_cube'
set.seed(2)
obs4 <- NULL
obs4$data <- array(runif(288)*280, dim = c(dataset = 1, member = 1, sdate = 6, 
                                           ftime = 3, lat = 4, lon = 4))
obs4$coords <- list(lon = lon, lat = lat)
class(obs4) <- 's2dv_cube'
exp_cor4 <- exp4
exp_cor4$data <- exp_cor4$data[, , 5:6, , , ]
class(exp_cor4) <- 's2dv_cube'

# dat5
exp5 <- exp4
obs5 <- obs4

set.seed(1)
res5 <- NULL
res5$data <- array(rnorm(length(exp5)), dim = c(member = 4, sdate = 6,
                   dataset = 1, ftime = 3, lat = 4, lon = 4))
class(res5) <- "s2dv_cube"

res5_1 <- NULL
res5_1$data <- array(rnorm(length(res5_1)), dim = c(member = 4, ftime = 3, 
                     dataset = 1, sdate = 6, lat = 4, lon = 4))
class(res5_1) <- "s2dv_cube"

# dat6
exp6 <- exp4
obs6 <- obs4
obs6$data <- s2dv::InsertDim(obs6$data, pos = 1, len = 4, name = 'window')

obs6_1 <- obs6
obs6_1$data[2] <- NA

exp6_1 <- exp6

exp6_1$data[1, , , 1, 1, 1] <- NA
exp_cor6_1 <- exp6_1
exp_cor6_1$data <- ClimProjDiags::Subset(exp_cor6_1$data, 'sdate', 1)
exp_cor6_2 <- exp6
exp_cor6_2$data <- ClimProjDiags::Subset(exp_cor6_2$data, 'member', 1:2)

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

test_that("1. Sanity checks", {
  # s2dv_cube
  expect_error(
    CST_QuantileMapping(exp = 1),
    paste0("Parameter 'exp' and 'obs' must be of the class 's2dv_cube', ",
           "as output by CSTools::CST_Load.")
  )
  expect_error(
    CST_QuantileMapping(exp = exp1),
    'argument "obs" is missing, with no default'
  )
  expect_error(
    CST_QuantileMapping(exp = exp1, obs = 1),
    paste0("Parameter 'exp' and 'obs' must be of the class 's2dv_cube', ",
           "as output by CSTools::CST_Load.")
  )
  expect_error(
    CST_QuantileMapping(exp = exp1, obs = obs1, exp_cor = 1),
    paste0("Parameter 'exp_cor' must be of the class 's2dv_cube', as output ",
    "by CSTools::CST_Load.")
  )
  # exp and obs
  expect_error(
    CST_QuantileMapping(exp = exp1_2, obs = obs1),
    "Parameter 'exp' must have dimension names."
  )
  expect_error(
    CST_QuantileMapping(exp = exp1, obs = obs1_2),
    "Parameter 'obs' must have dimension names."
  )
  # exp_cor
  expect_error(
    CST_QuantileMapping(exp = exp1, obs = obs1, exp_cor = exp_cor1, sdate_dim = 'time'),
    "Parameter 'exp_cor' must have dimension names."
  )
  # sdate_dim and memb_dim
  expect_error(
    CST_QuantileMapping(exp = exp1, obs = obs1, sdate_dim = 'time'),
    paste0("Parameter 'memb_dim' is not found in 'exp' dimensions.")
  )
  # window_dim
  expect_error(
    CST_QuantileMapping(exp = exp2, obs = obs2, window_dim = 'ftime'),
    paste0("Parameter 'window_dim' is not found in 'obs'.")
  )
  # method
  expect_error(
    CST_QuantileMapping(exp = exp2, obs = obs2, method = 'x'),
    paste0("Parameter 'method' must be one of the following methods: ",
           "'PTF', 'DIST', 'RQUANT', 'QUANT', 'SSPLIN'.")
  )
})

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

test_that("2. dat2, dat3 and dat4", {
  expect_equal(
    CST_QuantileMapping(exp = exp2, obs = obs2, window_dim = 'time'),
    res2
  )
  expect_equal(
    CST_QuantileMapping(exp = exp3, obs = obs3, window_dim = 'time', na.rm = T),
    res3
  )
  expect_equal(
    CST_QuantileMapping(exp = exp3, obs = obs3, window_dim = 'time'),
    res3_1
  )
  expect_equal(
    CST_QuantileMapping(exp = exp3_2, obs = obs3_2, window_dim = 'time'),
    res3_2
  )
  expect_equal(
    length(CST_QuantileMapping(exp4, obs4, exp_cor4)),
    3
  )
})

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

test_that("3. dat5", {
  expect_equal(
   dim(CST_QuantileMapping(exp5, obs5)$data),
   dim(res5$data)
  )
  expect_equal(
   dim(CST_QuantileMapping(exp5, obs5)$data),
   dim(res5$data)
  )
  expect_equal(
   dim(CST_QuantileMapping(exp5, obs5, sdate_dim = "ftime")$data),
   dim(res5_1$data)
  )
})

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

test_that("4. dat6", {
  expect_equal(
   CST_QuantileMapping(exp6, obs6, window_dim = 'window'),
   CST_QuantileMapping(exp6, obs6, window_dim = 'window', na.rm = TRUE)
  )
  expect_equal(
   dim(CST_QuantileMapping(exp6, obs6_1, window_dim = 'window')$data),
   c(member = 4, sdate = 6, dataset = 1, ftime = 3, lat = 4, lon = 4)
  )
  expect_equal(
    sum(is.na(CST_QuantileMapping(exp6_1, obs6_1, exp_cor = exp_cor6_1, window_dim = 'window', na.rm = TRUE)$data)),
    sum(is.na(exp_cor6_1$data))
  )
  expect_equal(
    dim(CST_QuantileMapping(exp6, obs6_1, exp_cor6_1, window_dim = 'window', na.rm = T)$data),
   c(dataset = 1, member = 4, sdate = 1, ftime = 3, lat = 4, lon = 4)
  )
  expect_equal(
    dim(CST_QuantileMapping(exp6, obs6_1, exp_cor6_2, window_dim = 'window')$data),
    c(dataset = 1, member = 2, sdate = 6, ftime = 3, lat = 4, lon = 4)
  )
})
