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

# dat1
set.seed(1)
exp1 <- array(rnorm(20), dim = c(sdate = 10, lat = 2))
set.seed(2)
obs1 <- array(rnorm(20), dim = c(sdate = 10, lat = 2))

# dat2
set.seed(1)
exp2 <- array(rnorm(40), dim = c(member = 2, sdate = 10, lat = 2))
set.seed(2)
obs2 <- array(rnorm(20), dim = c(member = 1, sdate = 10, lat = 2))

# dat3
set.seed(1)
exp3 <- array(rnorm(80), dim = c(member = 2, sdate = 10, lat = 2, dataset = 2))
set.seed(2)
obs3 <- array(rnorm(60), dim = c(sdate = 10, lat = 2, dataset = 3))

# dat4
set.seed(1)
exp4 <- array(rnorm(10), dim = c(sdate = 10))
exp4_1 <- array(exp4, dim = c(sdate = 10, dataset = 1))
set.seed(2)
obs4 <- array(rnorm(10), dim = c(sdate = 10))
obs4_1 <- array(obs4, dim = c(sdate = 10, dataset = 1))
obs4_2 <- obs4_1
obs4_2[c(1, 3)] <- NA

##############################################
test_that("1. Input checks", {
  # exp and obs (1)
  expect_error(
    Bias(c()),
    "Parameter 'exp' must be a numeric array."
  )
  expect_error(
    Bias(exp1, c()),
    "Parameter 'obs' must be a numeric array."
  )
  expect_error(
    Bias(exp1, array(rnorm(20), dim = c(10, lat = 2))),
    "Parameter 'exp' and 'obs' must have dimension names."
  )
  # time_dim
  expect_error(
    Bias(exp1, obs1, time_dim = 1),
    "Parameter 'time_dim' must be a character string."
  )
  expect_error(
    Bias(exp1, obs1, time_dim = 'time'),
    "Parameter 'time_dim' is not found in 'exp' or 'obs' dimension."
  )
  # memb_dim
  expect_error(
    Bias(exp1, obs1, memb_dim = TRUE),
    "Parameter 'memb_dim' must be a character string."
  )
  expect_error(
    Bias(exp1, obs1, memb_dim = 'memb'),
    "Parameter 'memb_dim' is not found in 'exp' dimension."
  )
  expect_error(
    Bias(exp2, array(rnorm(20), dim = c(member = 3, sdate = 10, lat = 2)), memb_dim = 'member'),
    "Not implemented for observations with members ('obs' can have 'memb_dim', but it should be of length = 1).", fixed = TRUE
  )
  # dat_dim
  expect_error(
    Bias(exp1, obs1, dat_dim = TRUE, ),
    "Parameter 'dat_dim' must be a character string."
  )
  expect_error(
    Bias(exp1, obs1, dat_dim = 'dat_dim'),
    "Parameter 'dat_dim' is not found in 'exp' or 'obs' dimension. Set it as NULL if there is no dataset dimension."
  )
  # exp, ref, and obs (2)
  expect_error(
    Bias(exp1, array(1:9, dim = c(sdate = 9))),
    "Parameter 'exp' and 'obs' must have same length of all dimensions except 'memb_dim' and 'dat_dim'."
  )
  # na.rm
  expect_error(
    Bias(exp2, obs2, memb_dim = 'member', na.rm = 1.5),
    "Parameter 'na.rm' must be one logical value."
  )
  # absolute
  expect_error(
    Bias(exp2, obs2, memb_dim = 'member', ncores = 1.5),
    "Parameter 'ncores' must be either NULL or a positive integer."
  )
  # time_mean
  expect_error(
    Bias(exp2, obs2, memb_dim = 'member', time_mean = 1.5),
    "Parameter 'time_mean' must be one logical value."
  )
  # ncores
  expect_error(
    Bias(exp2, obs2, memb_dim = 'member', ncores = 1.5),
    "Parameter 'ncores' must be either NULL or a positive integer."
  )

})

##############################################
test_that("2. Output checks: dat1", {

  expect_equal(
    dim(Bias(exp1, obs1)),
    c(lat = 2)
  )
  expect_equal(
    dim(Bias(exp1, obs1, time_mean = FALSE)),
    c(sdate = 10, lat = 2)
  )
  expect_equal(
    as.vector(Bias(exp1, obs1)),
    c(-0.07894886, 0.06907455),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(Bias(exp1, obs1, absolute = TRUE)),
    c(0.9557288, 0.8169118),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(Bias(exp1, obs1, time_mean = FALSE, na.rm = TRUE))[1:5],
    c(0.27046074, -0.00120586, -2.42347394, 2.72565648, 0.40975953),
    tolerance = 0.0001
  )

})

##############################################
test_that("3. Output checks: dat2", {

  expect_equal(
    dim(Bias(exp2, obs2, memb_dim = 'member')),
    c(lat = 2)
  )
  expect_equal(
    dim(Bias(exp2, obs2, memb_dim = 'member', time_mean = FALSE)),
    c(sdate = 10, lat = 2)
  )
  expect_equal(
    as.vector(Bias(exp2, obs2, memb_dim = 'member')),
    c(-0.02062777, -0.18624194),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(Bias(exp2, obs2, memb_dim = 'member', time_mean = FALSE)[1:2,1:2]),
    c(0.6755093, 0.1949769, 0.4329061, -1.9391461),
    tolerance = 0.0001
  )

})

##############################################
test_that("4. Output checks: dat3", {

  expect_equal(
    dim(Bias(exp3, obs3, memb_dim = 'member', dat_dim = 'dataset')),
    c(nexp = 2, nobs = 3, lat = 2)
  )
  expect_equal(
    dim(Bias(exp3, obs3, memb_dim = 'member', dat_dim = 'dataset', time_mean = FALSE)),
    c(sdate = 10, nexp = 2, nobs = 3, lat = 2)
  )
  expect_equal(
    as.vector(Bias(exp3, obs3, memb_dim = 'member', dat_dim = 'dataset'))[5:10],
    c(0.23519286, 0.18346575, -0.18624194, -0.07803352, 0.28918537, 0.39739379),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(Bias(exp3, obs3, memb_dim = 'member', dat_dim = 'dataset', absolute = TRUE, time_mean = FALSE))[5:10],
    c(0.2154482, 0.8183919, 2.1259250, 0.7796967, 1.5206510, 0.8463483),
    tolerance = 0.0001
  )
  expect_equal(
    as.vector(Bias(exp2, obs2, memb_dim = 'member')),
    as.vector(Bias(exp3, obs3, memb_dim = 'member', dat_dim = 'dataset')[1,1,])
  )
  expect_equal(
    as.vector(Bias(exp2, obs2, memb_dim = 'member', time_mean = FALSE)),
    as.vector(Bias(exp3, obs3, memb_dim = 'member', dat_dim = 'dataset', time_mean = FALSE)[ ,1,1,])
  )

})

##############################################
test_that("5. Output checks: dat4", {
  expect_equal(
    dim(Bias(exp4, obs4)),
    NULL
  )
  expect_equal(
    dim(Bias(exp4, obs4, time_mean = F)),
    c(sdate = 10)
  )
  expect_equal(
    as.vector(Bias(exp4, obs4, time_mean = F)),
    as.vector(exp4 - obs4)
  )
  expect_equal(
    as.vector(Bias(exp4, obs4, time_mean = F, absolute = T)),
    abs(as.vector(exp4 - obs4))
  )
  expect_equal(
    as.vector(Bias(exp4, obs4, absolute = T)),
    mean(abs(as.vector(exp4 - obs4)))
  )

  expect_equal(
    dim(Bias(exp4_1, obs4_1, dat_dim = 'dataset')),
    c(nexp = 1, nobs = 1)
  )
  expect_equal(
    dim(Bias(exp4_1, obs4_1, dat_dim = 'dataset', time_mean = F)),
    c(sdate = 10, nexp = 1, nobs = 1)
  )
  expect_equal(
    as.vector(Bias(exp4_1, obs4_1, dat_dim = 'dataset', time_mean = F)),
    as.vector(Bias(exp4, obs4, time_mean = F))
  )
  # 4_2: NA
  expect_equal(
    as.vector(Bias(exp4_1, obs4_2, dat_dim = 'dataset')),
    as.numeric(NA)
  )
  expect_equal(
    as.vector(Bias(exp4_1, obs4_2, dat_dim = 'dataset', time_mean = F))[c(1, 3)],
    as.numeric(c(NA, NA))
  )
  expect_equal(
    as.vector(Bias(exp4_1, obs4_2, dat_dim = 'dataset', time_mean = F))[c(2, 4:10)],
    as.vector(Bias(exp4, obs4, time_mean = F))[c(2, 4:10)]
  )
})
