test_that("make_bar", {
  chars <- withr::with_options(list(cli.unicode = FALSE), progress_chars())
  lapply(
    seq(0, 1, by = 0.2),
    function(p) {
      expect_equal(nchar(cli::ansi_strip(make_bar(chars, p, 10))), 10)
    }
  )
})

test_that("initial state", {
  local_cli_config()

  # num = 0, nch = 0, cbt = 0
  # no downloads are needed, all installed
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "installed"   ,
            10000 ,
    "foo"         ,
    NA_character_ ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    "miss"        ,
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num = 0, nch = 1, cbt > 0
  # no downloads needed, all cached or installed
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "hit"         ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    "hit"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num = 0, nch = 1, cbt > 0
  # no downloads needed, but cached size known
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "hit"         ,
    "cran"        ,
            10000 ,
    "foo2"        ,
    "hit"         ,
    "installed"   ,
            10000 ,
    "foo3"        ,
    "hit"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num = 0, nch = 1, cbt = 0
  # no downloads needed, cached size unknown
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
    NA_integer_   ,
    "foo"         ,
    "hit"         ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    "hit"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num > 0, bts > 0, unk = 0, nch = 0, cbt = 0
  # nothing is cached, sizes known
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
            20000 ,
    "bar"         ,
    "miss"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num > 0, bts > 0, unk = 0, nch = 1, cbt = 0
  # 1 package cached, 2 downloaded, cached size unknown
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
            20000 ,
    "bar"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    NA_character_ ,
    "cran"        ,
    NA_integer_   ,
    "bar2"        ,
    "hit"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num > 0, bts > 0, unk = 0, nch = 1, cbt > 0
  # 1 package cached, 2 downloaded, cached size known
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
            20000 ,
    "bar"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    NA_character_ ,
    "cran"        ,
            20000 ,
    "bar2"        ,
    "hit"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num > 0, bts > 0, unk > 0, nch = 0, cbt = 0
  # downloads with unknown sizes
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            20000 ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
    NA_integer_   ,
    "bar"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    NA_character_
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num > 0, bts > 0, unk > 0, nch = 1, cbt > 0
  # downloads with known & unknown sizes, 1 cached with known size
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
    NA_integer_   ,
    "bar"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    NA_character_ ,
    "cran"        ,
            30000 ,
    "bar2"        ,
    "hit"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num > 0, bts > 0, unk > 0, nch = 1, cbt = 0
  # downloads with known sizes, 1 cached with unknown size
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
    NA_integer_   ,
    "bar"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    NA_character_ ,
    "cran"        ,
    NA_integer_   ,
    "bar2"        ,
    "hit"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num > 0, bts = 0, unk > 0, nch = 0, cbt = 0
  # downloads with only unknown sizes, nothing cached
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
    NA_integer_   ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
    NA_integer_   ,
    "bar"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    NA_character_
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num > 0, bts = 0, unk > 0, nch = 1, cbt = 0
  # downloads with unknown sizes, 1 cached with unknown size
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
    NA_integer_   ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
    NA_integer_   ,
    "bar"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    NA_character_ ,
    "cran"        ,
    NA_integer_   ,
    "bar2"        ,
    "hit"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))

  # num > 0, bts = 0, unk > 0, nch = 1, cbt > 0
  # downloads with unknown sizes, 1 cached
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
    NA_integer_   ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
    NA_integer_   ,
    "bar"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    NA_character_ ,
    "cran"        ,
            30000 ,
    "bar2"        ,
    "hit"
  )
  expect_snapshot(invisible(
    pkgplan__create_progress_bar(what)
  ))
})

test_that("data updates", {
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    "miss"        , # no download, installed
    "cran"        ,
            20000 ,
    "bar"         ,
    "hit"         , # no download, cached
    "cran"        ,
            20000 ,
    "bar2"        ,
    "miss"
  )

  expect_snapshot({
    bar <- pkgplan__create_progress_bar(what = what)
    pkgplan__update_progress_bar(
      bar,
      1L,
      "data",
      list(current = 5000, total = 10000)
    )
    pkgplan__update_progress_bar(
      bar,
      4L,
      "data",
      list(current = 20000, total = 20000)
    )
    pkgplan__done_progress_bar(bar)
    bar$what
  })
})

test_that("all finish messages for updates", {
  do <- function(
    idx,
    event = "done",
    download_status = "Got",
    make_tempfile = TRUE
  ) {
    bar <- pkgplan__create_progress_bar(what = what)
    tmp <- tempfile()
    if (make_tempfile) {
      writeBin(raw(7), tmp)
      on.exit(unlink(tmp), add = TRUE)
    }
    pkgplan__update_progress_bar(
      bar,
      idx,
      event,
      list(
        download_status = download_status,
        package = "foo",
        platform = "source",
        version = "1.0.0",
        fulltarget = tmp,
        fulltarget_tree = tempfile()
      )
    )
    pkgplan__done_progress_bar(bar)
    bar$what
  }

  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    "miss"        , # no download, installed
    "cran"        ,
            20000 ,
    "bar"         ,
    "hit"         , # no download, cached
    "cran"        ,
            20000 ,
    "bar2"        ,
    "miss"
  )

  expect_snapshot(do(1L))
  expect_snapshot(do(1L, make_tempfile = FALSE))
  expect_snapshot(do(1L, event = "error"))
})

test_that("rate", {
  now <- Sys.time()
  chunks <- as.environment(list(
    "0" = 1000,
    "1" = 2000,
    "2" = 0,
    "3" = 400,
    "4" = 100,
    "5" = 200
  ))

  r <- calculate_rate(now - 5.5, now, chunks)
  expect_equal(r, list(rate = 200, rstr = "0.2 kB/s"))
})

test_that("eta", {
  expect_equal(
    calculate_eta(100, 50, 0),
    list(etas = NA, estr = "??s ")
  )
  expect_equal(
    calculate_eta(100, 50, 10),
    list(etas = as.difftime(5, units = "secs"), estr = "~5s   ")
  )
})

test_that("parts are calculated properly", {
  local_cli_config()
  what <- tibble::tribble(
    ~type         ,
    ~filesize     ,
    ~package      ,
    ~cache_status ,
    "cran"        ,
            10000 ,
    "foo"         ,
    "miss"        ,
    "cran"        ,
            20000 ,
    "bar"         ,
    "miss"        ,
    "installed"   ,
            10000 ,
    "foo2"        ,
    NA_character_ ,
    "cran"        ,
            20000 ,
    "bar2"        ,
    "hit"
  )

  expect_snapshot(
    bar <- pkgplan__create_progress_bar(what)
  )
  parts <- calculate_progress_parts(bar)
  expect_equal(parts$pkg_done, "0")
  expect_equal(parts$pkg_total, "2")
  expect_equal(parts$percent, "  0%")
  expect_match(parts$rate, "^\\s+$")
  expect_equal(parts$msg, "Connecting...")
  expect_match(cli::ansi_strip(parts$line), "^[(][\\s\u00a0]+[)]$", perl = TRUE)
  expect_equal(parts$eta, "??s ")
})

test_that("parts if file size is unknown", {
  # TODO
  expect_true(TRUE)
})

test_that("status bar is cleaned up on interrupt / error", {
  # TODO
  expect_true(TRUE)
})
