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

# dat1
data <- rnorm(2 * 10 * 4 * 5 * 6 * 7)
dim(data) <- c(dataset = 2, member = 10,
                sdate = 4, ftime = 5, lat = 6, lon = 7)
lon <- seq(0, 12, 2)
lat <- seq(10, 15, 1)
coords <- list(lon = lon, lat = lat)
exp <- list(data = data, coords = coords)
attr(exp, "class") <- "s2dv_cube"

# dat2
exp2 <- exp
exp2$attrs <- list(source_files = 'exp')
exp2$coords <- NULL
exp2_2 <- exp2
exp2_2$coords <- list(long = seq(1:4), lati = seq(1:4))
##############################################
test_that("1. Input checks", {
  # Check 's2dv_cube'
  expect_error(
    CST_EnsClustering(rnorm(2 * 15 * 4 * 5 * 6 * 7)),
    paste0("Parameter 'exp' must be of the class 's2dv_cube', ",
           "as output by CSTools::CST_Load.")
  )
  # Check 'exp' object structure
  expect_error(
    CST_EnsClustering(exp2),
    paste0("Parameter 'exp' must have 'data' and 'coords' elements ",
           "within the 's2dv_cube' structure.")
  )
  expect_error(
    CST_EnsClustering(exp2_2),
    paste0("Spatial coordinate names do not match any of the names accepted by ",
           "the package. Latitudes accepted names: 'lat', 'lats', 'latitude',", 
           " 'y', 'j', 'nav_lat'. Longitudes accepted names: 'lon', 'lons',", 
           " 'longitude', 'x', 'i', 'nav_lon'.")
  )
  expect_error(
    EnsClustering(array(rnorm(8400), dim = c(member = 10, sdate = 4, ftime = 5, 
                                             lati = 6, loni = 7)), 
                  lat = seq(1:5), lon = seq(1:6)),
    paste0("Spatial coordinate names do not match any of the names accepted by ",
           "the package.")
  )
  # Checks in Analogs function
  expect_error(
    CST_EnsClustering(exp, time_moment = "invalid"),
    "Invalid time_moment"
  )
  exp$coords$lat <- 1
  expect_error(
    CST_EnsClustering(exp),
    "Incorrect lat length"
  )
  exp$coords$lon <- 1
  exp$coords$lat <- lat
  expect_error(
    CST_EnsClustering(exp),
    "Incorrect lon length"
  )
  exp$coords$lon <- lon
})

test_that("2. Output checks", {
  # Sanity checks on dimensions
  res <- CST_EnsClustering(exp, numclus = 3)
  expect_equal(
    dim(res$cluster),
    dim(exp$data)[c(2, 1, 3)]
  )
  res <- CST_EnsClustering(exp, numclus = 3, cluster_dim = "sdate")
  expect_equal(
    dim(res$cluster),
    dim(exp$data)[c(3, 1, 2)]
  )
  res <- CST_EnsClustering(exp, numclus = 3,
                           cluster_dim = c("member", "dataset", "sdate"))
  expect_equal(
    dim(res$cluster),
    dim(exp$data)[c(2, 1, 3)]
  )
  res <- CST_EnsClustering(exp, numclus = 3, cluster_dim = c("member", "sdate"))
  expect_equal(
    dim(res$cluster),
    dim(exp$data)[c(2, 3, 1)]
  )
  expect_equal(
    dim(res$freq),
    c(cluster = 3, dim(exp$data)[1])
  )
  expect_equal(
    dim(res$closest_member$sdate),
    c(cluster = 3, dim(exp$data)[1])
  )
  expect_equal(
    dim(res$repr_field),
    c(cluster = 3, dim(exp$data)[c(5, 6)], dim(exp$data)[1])
  )
  expect_equal(
    dim(res$composites), 
    c(cluster = 3, dim(exp$data)[c(5, 6)], dim(exp$data)[1])
  )

  # Functionality tests
  res <- CST_EnsClustering(exp, numclus = 3, variance_explained = 80,
                           cluster_dim = "member")
  # The closest member of each cluster should be member of that cluster
  for (i in 1:3) {
    expect_equivalent(res$cluster[res$closest_member$member[i, 1, 1], 1, 1], i)
  }

  res <- CST_EnsClustering(exp, numclus = 3, numpcs = 8,
                     cluster_dim = c("member"))
  for (i in 1:3) {
    expect_equivalent(res$cluster[res$closest_member$member[i, 1, 1], 1, 1], i)
  }

  res <- CST_EnsClustering(exp, numclus = 3, variance_explained = 80,
                     cluster_dim = c("member"))

  # The weighted mean of all cluster mean fields should be 0
  comp1 <- sweep(res$composites, c(1, 4, 5), res$freq / 100, "*")
  cmean <- apply(comp1, c(2, 3, 4, 5), mean)[ , , 1, 1]
  expect_equal(mean(cmean), 0., tolerance = 1e-10)

  # This should give a different result
  res2 <- CST_EnsClustering(exp, numclus = 3, variance_explained = 80,
                      cluster_dim = c("member"),
                      lat_lim = c(10, 12), lon_lim = c(0, 6))
  expect_gt(sum((res$cluster - res2$cluster)^2), 0)
})
