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

# cube1
dates_data1 <- c(seq(as.Date("11-07-1993", "%d-%m-%Y", tz = 'UTC'),
                     as.Date("20-07-1993","%d-%m-%Y", tz = 'UTC'), "day"),
                 seq(as.Date("11-07-1994", "%d-%m-%Y", tz = 'UTC'),
                     as.Date("20-07-1994","%d-%m-%Y", tz = 'UTC'), "day"))
dim(dates_data1) <- c(time = 10, sdate = 2)
cube1 <- NULL
cube1$data <- array(1:(2*10*2), c(time = 10, sdate = 2, member = 2))
cube1$attrs$Dates <- dates_data1
class(cube1) <- 's2dv_cube'
ref_dates1 <- c(seq(as.Date("01-07-1993", "%d-%m-%Y", tz = 'UTC'),
                    as.Date("10-07-1993","%d-%m-%Y", tz = 'UTC'), "day"),
                seq(as.Date("01-07-1994", "%d-%m-%Y", tz = 'UTC'),
                    as.Date("10-07-1994","%d-%m-%Y", tz = 'UTC'), "day"))
dim(ref_dates1) <- c(time = 10, sdate = 2)
cube_ref <- NULL
cube_ref$data <- array(1001:1020, c(time = 10, sdate = 2))
cube_ref$attrs$Dates <- ref_dates1
class(cube_ref) <- 's2dv_cube'
start1 <- list(3, 7)
end1 <- list(10, 7)
start2 <- list(11, 7)
end2 <- list(15, 7)

# dat1
ref1 <- array(1001:1020, c(time = 10, sdate = 2, member = 1))
data1 <- array(1:40, c(time = 10, sdate = 2, member = 2))


# dat2
ref2 <- array(1001:1015, c(time = 5, sdate = 1, member = 3))
data2 <- array(1:6, c(time = 3, sdate = 1, member = 2))

###########################################################################
test_that("1. Input checks", {
  # 's2dv_cube'
  expect_error(
    CST_MergeRefToExp('a'),
    "Parameter 'data1' must be of the class 's2dv_cube'."
  )
  expect_error(
    CST_MergeRefToExp(cube1, array(10)),
    "Parameter 'data2' must be of the class 's2dv_cube'."
  )
  # data
  expect_error(
    MergeRefToExp(10, 10),
    "Parameters 'data1' and 'data2' must be arrays."
  )
  expect_error(
    MergeRefToExp(array(10), array(10)),
    "Parameters 'data1' and 'data2' must have named dimensions."
  )
  # time_dim
  expect_error(
    MergeRefToExp(data1 = ref1, data2 = data1, time_dim = 1),
    "Parameter 'time_dim' must be a character string."
  )
  expect_error(
    MergeRefToExp(data1 = ref1, data2 = data1, time_dim = 'ftime'),
    paste0("Parameter 'time_dim' is not found in 'data1' or 'data2' dimension ",
           "names.")
  )
  # memb_dim
  expect_error(
    MergeRefToExp(data1 = ref1, data2 = data1, memb_dim = 1),
    "Parameter 'memb_dim' must be a character string."
  )
  expect_error(
    MergeRefToExp(data1 = ref1, data2 = data1, memb_dim = 'ensemble'),
    paste0("Parameter 'memb_dim' is not found in 'data1' or 'data2' dimension. ",
           "Set it to NULL if there is no member dimension.")
  )
  # common dimensions
  expect_error(
    MergeRefToExp(data1 = array(1:12, c(sdate = 2, time = 2, dat = 3)),
                  data2 = array(1:16, c(sdate = 2, time = 2, var = 4)),
                  memb_dim = NULL),
    paste0("Parameter 'data1' and 'data2' must have same length of ",
           "all dimensions except 'memb_dim'.")
  )
  expect_error(
    MergeRefToExp(data1 = array(1:12, c(sdate = 2, time = 2, dat = 1)),
                  data2 = array(1:16, c(sdate = 2, time = 2)),
                  memb_dim = NULL),
    paste0("Parameter 'data1' and 'data2' must have same length of ",
           "all dimensions except 'memb_dim'.")
  )
  # dates
  expect_warning(
    MergeRefToExp(data1 = array(1:4, c(sdate = 2, time = 2, lat = 1)),
                  data2 = array(1:16, c(sdate = 2, time = 2, lat = 1)),
                  memb_dim = NULL, start1 = list(1, 1), end1 = list(3, 1), 
                  start2 = NULL, end2 = NULL),
    paste0("Parameter 'dates' is NULL and the average of the ",
           "full data provided in 'data' is computed.")
  )
  expect_warning(
    MergeRefToExp(data1 = ref1,
                  data2 = data1, dates1 = ref_dates1, dates2 = dates_data1,
                  start1 = c(3, 7), end1 = end1, 
                  start2 = start2, end2 = end2),
    paste0("Parameter 'start1' and 'end1' must be lists indicating the ",
           "day and the month of the period start and end. Full data ",
           "will be used.")
  )
  expect_warning(
    MergeRefToExp(data1 = ref1,
                  data2 = data1, dates1 = as.vector(ref_dates1), 
                  dates2 = dates_data1, start1 = start1, end1 = end1, 
                  start2 = start2, end2 = end2),
    paste0("Parameter 'dates1' must have named dimensions if 'start' and ",
                "'end' are not NULL. All 'data1' will be used.")
  )
})

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

test_that("2. Output checks: CST_MergeRefToExp", {
  res1 <- CST_MergeRefToExp(data1 = cube_ref, data2 = cube1, 
                            start1 = start1, end1 = end1,
                            start2 = start2, end2 = end2)
  # dims
  expect_equal(
    dim(res1$data),
    res1$dims
  )
  # coords
  expect_equal(
    names(dim(res1$data)),
    names(res1$coords)
  )
  # Dates
  expect_equal(
    dim(res1$data)[c('time', 'sdate')],
    dim(res1$attrs$Dates)
  )
  # data
  expect_equal(
    res1$data[1:8,,1],
    res1$data[1:8,,2]
  )
})

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

test_that("3. Output checks: MergeRefToExp", {
  # Minimum dimensions
  expect_equal(
    MergeRefToExp(data1 = array(1:2, c(time = 2)),
                  data2 = array(1, c(time = 1)), memb_dim = NULL),
    array(c(1,2,1), dim = c(time = 3))
  )
  # res2
  res2 <- MergeRefToExp(data1 = ref1, data2 = data1)
  ## dims
  expect_equal(
    dim(res2),
    c(time = 20, sdate = 2, member = 2)
  )
  ## data
  expect_equal(
    res2[,1,],
    array(c(1001:1010, 1:10, 1001:1010, 21:30), dim = c(time = 20, member = 2))
  )
  # res3: multiple different members
  res3 <- MergeRefToExp(data1 = ref2, data2 = data2)
  ## dims
  expect_equal(
    dim(res3),
    c(time = 8, sdate = 1, member = 6)
  )
  expect_equal(
    as.vector(res3[1:5, 1, ]),
    c(rep(1001:1005, 2), rep(1006:1010, 2), rep(1011:1015, 2))
  )
  expect_equal(
    as.vector(res3[6:8, 1, ]),
    rep(c(1:3, 4:6), 3)
  )
})

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

test_that("3. Output checks: Dates", {
  data_dates <- c(seq(as.Date("01-07-1993", "%d-%m-%Y", tz = 'UTC'),
                      as.Date("01-12-1993", "%d-%m-%Y", tz = 'UTC'), "day"),
                  seq(as.Date("01-07-1994", "%d-%m-%Y", tz = 'UTC'),
                      as.Date("01-12-1994","%d-%m-%Y", tz = 'UTC'), "day"))

  dim(data_dates) <- c(time = 154, sdate = 2)
  ref_dates <- seq(as.Date("01-01-1993", "%d-%m-%Y", tz = 'UTC'),
                   as.Date("01-12-1994", "%d-%m-%Y", tz = 'UTC'), "day")
  dim(ref_dates) <- c(time = 350, sdate = 2)
  ref <- NULL
  ref$data <- array(1001:1700, c(time = 350, sdate = 2))
  ref$attrs$Dates <- ref_dates
  class(ref) <- 's2dv_cube'
  data <- NULL
  data$data <- array(1:(2 * 154 * 2), c(time = 154, sdate = 2, member= 2))
  data$attrs$Dates <- data_dates
  class(data) <- 's2dv_cube'

  suppressWarnings(
    expect_equal(CST_MergeRefToExp(data1 = ref, data2 = data, start1 = list(21, 6),
                                  end1 = list(30, 6), start2 = list(1, 7),  
                                  end2 = list(21, 9))$attrs$Dates, 
                 SelectPeriodOnDates(ref_dates, start = list(21, 6), end = list(21,9)))
  )

  output <- array(c(1172:1181, 1:83, 1537:1546, 155:237, 1172:1181, 309:391,
                    1537:1546, 463:545), c(time = 93, sdate = 2, member = 2)) 

  expect_equal(
    CST_MergeRefToExp(data1 = ref, data2 = data, start1 = list(21, 6),
                                 end1 = list(30, 6), start2 = list(1, 7),
                                 end2 = list(21, 9))$data, 
    output
  )


  # issue 13: One lead time
  data_dates <- c(as.Date("01-06-1993", "%d-%m-%Y", tz = 'UTC'),
                  as.Date("01-07-1993", "%d-%m-%Y", tz = 'UTC'),
                  as.Date("01-06-1994", "%d-%m-%Y", tz = 'UTC'),
                  as.Date("01-07-1994","%d-%m-%Y", tz = 'UTC'))

  dim(data_dates) <- c(time = 2, sdate = 2)
  ref_dates <- c(as.Date("01-05-1993", "%d-%m-%Y", tz = 'UTC'),
                 as.Date("01-05-1994", "%d-%m-%Y", tz = 'UTC'))
  dim(ref_dates) <- c(time = 1, sdate = 2)
  ref <- NULL
  ref$data <- array(1:2, c(time = 1, sdate = 2))
  ref$attrs$Dates <- ref_dates
  class(ref) <- 's2dv_cube'
  data <- NULL
  data$data <- array(1:(2 * 3 * 2), c(time = 2, sdate = 2, member = 3))
  data$attrs$Dates <- data_dates
  class(data) <- 's2dv_cube'

  res_dates <- c(as.Date("01-05-1993", "%d-%m-%Y", tz = 'UTC'),
                 as.Date("01-06-1993", "%d-%m-%Y", tz = 'UTC'),
                 as.Date("01-07-1993", "%d-%m-%Y", tz = 'UTC'),
                 as.Date("01-05-1994", "%d-%m-%Y", tz = 'UTC'),
                 as.Date("01-06-1994", "%d-%m-%Y", tz = 'UTC'),
                 as.Date("01-07-1994","%d-%m-%Y", tz = 'UTC'))
  dim(res_dates) <- c(time = 3, sdate = 2)

  expect_equal(
    CST_MergeRefToExp(data1 = ref, data2 = data, start1 = list(1, 5),
                                 end1 = list(31, 5), start2 = list(1, 6),
                                 end2 = list(31, 7))$attrs$Dates,
    res_dates
  )

  output <- abind::abind(t(matrix(rep(1:2, 3), ncol = 2, nrow = 3, byrow = T)),
                         data$data, along = 1)
  names(dim(output)) <- c('time', 'sdate', 'member')

  expect_equal(
    CST_MergeRefToExp(data1 = ref, data2 = data, start1 = list(1, 5),
                                 end1 = list(31, 5), start2 = list(1, 6),
                                 end2 = list(31, 7))$data,
    output
  )
})

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

test_that("4. Test Seasonal", {
  dates <- NULL 
  hcst.inityear <- 1993
  hcst.endyear <- 2017
  for (year in hcst.inityear:hcst.endyear){
    dates <- c(dates, format(seq(as.Date(paste0("01-04-",year), "%d-%m-%Y",
                                         tz = 'UTC'),
                                 as.Date(paste0("01-11-",year), "%d-%m-%Y",
                                         tz = 'UTC'), "day"), "%Y-%m-%d"))
  }
  dates <- as.Date(dates, tz = 'UTC')
  dim.dates <- c(time = 215, sweek = 1, sday = 1,
                 sdate = (hcst.endyear - hcst.inityear) + 1)
  dim(dates) <- dim.dates
  ref <- NULL
  ref$data <- array(1:(215*25), c(time = 215, sdate = 25))
  ref$attrs$Dates <- dates
  class(ref) <- 's2dv_cube'
  data <- NULL
  data$data <- array(1:(215*25*3), c(time = 215, sdate = 25, member=3))
  data$attrs$Dates <- dates
  class(data) <- 's2dv_cube'

  expect_equal(
    CST_MergeRefToExp(data1 = data, data2 = ref, start1 = list(21, 6),
                      end1 = list(30, 6), start2 = list(1, 7),  
                      end2 = list(21, 9))$attrs$Dates, 
    SelectPeriodOnDates(dates, start = list(21, 6), end = list(21,9))
  )
  
  expect_equal(
    CST_MergeRefToExp(data1 = ref, data2 = data, start1 = list(21, 6),
                                 end1 = list(30, 6), start2 = list(1, 7),  
                                 end2 = list(21, 9))$attrs$Dates, 
    SelectPeriodOnDates(dates, start = list(21, 6), end = list(21,9))
  )
})
