test_that("Basic ops on iris task", {
  task = tsk("iris")
  expect_task(task)
  expect_task_supervised(task)
  expect_task_classif(task)
  expect_equal(task$target_names, "Species")
  expect_set_equal(task$class_names, levels(iris$Species))

  f = task$formula()
  expect_class(f, "formula")
  # expect_set_equal(attr(terms(f), "term.labels"), setdiff(names(iris), "Species"))
})

test_that("$class_names consider also inactive rows", {
  task = tsk("iris")
  task$set_row_roles(1:100, remove_from = "use")

  expect_set_equal(task$class_names, levels(iris$Species))
})

test_that("Factor levels are preserved in prediction", {
  task = tsk("iris")
  learner = lrn("classif.featureless")
  learner$predict_type = "prob"
  learner$train(task, 1:100)

  pred = as.data.table(learner$predict(task, 1:10))
  expect_factor(pred$truth, levels = levels(iris$Species), any.missing = FALSE)
  expect_factor(pred$response, levels = levels(iris$Species), any.missing = FALSE)
  expect_equal(levels(pred$truth), levels(pred$response))
  expect_numeric(pred$prob.virginica, lower = 0, upper = 0, any.missing = FALSE)

  pred = as.data.table(learner$predict(task, 101:150))
  expect_factor(pred$truth, levels = levels(iris$Species), any.missing = FALSE)
  expect_factor(pred$response, levels = levels(iris$Species), any.missing = FALSE)
  expect_equal(levels(pred$truth), levels(pred$response))
  expect_numeric(pred$prob.virginica, lower = 0, upper = 0, any.missing = FALSE)
})

test_that("Target is character/factor", {
  b = as_data_backend(iris)
  expect_error(TaskClassif$new("iris", backend = b, target = "Sepal.Length"), "Target column")
})

test_that("TaskClassif rejects NAs in target", {
  dt = data.table::data.table(x = 1:10, y = factor(c(NA, letters[1:9])))
  expect_message(as_task_classif(dt, target = "y"), "contains missing")
})

test_that("0 feature task", {
  b = as_data_backend(iris[, 5L, drop = FALSE])
  task = TaskClassif$new(id = "zero_feat_task", b, target = "Species")
  expect_output(print(task))
  b = task$backend
  expect_backend(b)
  expect_task(task)
  expect_task_supervised(task)
  expect_task_classif(task)
  expect_data_table(task$data(), ncols = 1L)

  lrn = lrn("classif.featureless")
  p = lrn$train(task)$predict(task)
  expect_prediction(p)
})

test_that("Positive class always comes first", {
  sonar = load_dataset("Sonar", package = "mlbench")
  tmp = list(c("M", "R"), c("R", "M"))
  lrn = lrn("classif.featureless", predict_type = "prob", method = "sample")

  for (lvls in tmp) {
    task = TaskClassif$new("sonar", backend = sonar, target = "Class", positive = lvls[[1]])
    expect_equal(task$positive, lvls[1])
    expect_equal(task$negative, lvls[2])
    expect_equal(task$class_names, lvls)
    expect_equal(levels(task$truth()), lvls)
    expect_equal(levels(task$data(cols = task$target_names)[[1L]]), lvls)
    preds = lrn$train(task)$predict(task)
    expect_equal(levels(preds$truth), lvls)
    expect_equal(levels(preds$response), lvls)
    expect_set_equal(colnames(preds$prob), lvls)
  }
})

test_that("class property is updated", {
  task = tsk("iris")

  task$filter(1:100)
  expect_subset("multiclass", task$properties)
  task$droplevels()
  expect_subset("twoclass", task$properties)
  task$filter(1:50)
  expect_subset("twoclass", task$properties)
  expect_error(task$droplevels())

  task$rbind(iris)
  task$droplevels()
  expect_subset("multiclass", task$properties)
})


test_that("droplevels keeps level order", {
  task = tsk("iris")
  my_order = c("virginica", "setosa", "versicolor")
  task$col_info[id == "Species", levels := list(my_order)]
  lvls = task$class_names
  expect_equal(lvls, my_order)
  task$filter(c(101:150, 1:50)) # remove versicolor
  task$droplevels()
  expect_equal(task$class_names, c("virginica", "setosa"))
})

test_that("target is encoded as factor (#629)", {
  dt = data.table(a = c(1, 2, 3, 4), target = c(1, 1, 0, 1))
  expect_error(TaskClassif$new(id = "XX", backend = dt, target = "target"), "factor")

  dt$target = ordered(dt$target)
  TaskClassif$new(id = "XX", backend = dt, target = "target")
})

test_that("offset column role works with binary tasks", {
  task = tsk("pima")
  expect_null(task$offset)

  task$set_col_roles("age", "offset")
  expect_subset("offset", task$properties)
  expect_data_table(task$offset, nrows = task$nrow, ncols = 2)
  expect_subset(c("row_id", "offset"), names(task$offset))

  expect_error(
    {
      task$col_roles$offset = c("glucose", "diabetes")
    },
    "There may only be up to one column with role"
  )

  expect_error(
    {
      task$col_roles$offset = c("glucose")
    },
    "contain missing values"
  )

  expect_warning(lrn("classif.rpart")$train(task), "has offset")
})

test_that("offset column role works with multiclass tasks", {
  task = tsk("penguins")
  expect_null(task$offset)
  task$set_col_roles("year", "offset")
  expect_subset("offset", task$properties)
  expect_data_table(task$offset, nrows = task$nrow, ncols = 2)
  expect_subset(c("row_id", "offset"), names(task$offset))

  expect_error(
    {
      task$col_roles$offset = "bill_length"
    },
    "contain missing values"
  )

  task = tsk("wine")

  expect_error(
    {
      task$col_roles$offset = c("alcohol", "ash")
    },
    "Must be a subset of"
  )

  task = tsk("wine")
  data = task$data()
  set(data, j = "offset_1", value = runif(nrow(data)))
  set(data, j = "offset_2", value = runif(nrow(data)))
  task = as_task_classif(data, target = "type")
  task$set_col_roles(c("offset_1", "offset_2"), "offset")

  expect_subset("offset", task$properties)
  expect_data_table(task$offset, nrows = task$nrow, ncols = 3)
  expect_subset(c("row_id", "offset_1", "offset_2"), names(task$offset))
})
