test_that("reverse_geo_lite() rejects nonnumeric and mismatched coordinates", {
  expect_snapshot(error = TRUE, reverse_geo_lite(0, c(2, 3)))
  expect_snapshot(error = TRUE, reverse_geo_lite("a", "a"))
})

test_that("reverse_geo_lite() reports and clamps coordinates outside bounds", {
  skip_nominatim_ci()

  expect_snapshot(out <- reverse_geo_lite(0, 200))
  chk <- dplyr::tibble(lat = 0, lon = 180)
  expect_identical(out[, c("lat", "lon")], chk)

  expect_snapshot(out <- reverse_geo_lite(200, 0))
  chk <- dplyr::tibble(lat = 90, lon = 0)
  expect_identical(out[, c("lat", "lon")], chk)
})


test_that("reverse_geo_lite() returns a typed row when no address matches", {
  local_mocked_bindings(api_call = function(...) {
    test_fixture("reverse-error.json")
  })

  expect_snapshot(obj <- reverse_geo_lite(89.999999, 179.9999))

  expect_equal(nrow(obj), 1)
  expect_equal(obj$lat, 89.999999)
  expect_equal(obj$lon, 179.9999)
  expect_s3_class(obj, "tbl")
  expect_named(obj, c("address", "lat", "lon"))
  expect_equal(
    vapply(obj, class, FUN.VALUE = character(1)),
    c(address = "character", lat = "numeric", lon = "numeric")
  )
  expect_equal(obj$address, NA_character_)

  expect_snapshot(
    obj_renamed <- reverse_geo_lite(89.999999, 179.9999, address = "adddata")
  )

  expect_named(obj_renamed, c("adddata", "lat", "lon"))

  names(obj_renamed) <- names(obj)

  expect_identical(obj, obj_renamed)
})


test_that("reverse_geo_lite() returns a non-spatial tibble", {
  skip_nominatim_ci()

  obj <- reverse_geo_lite(40.4168, -3.7038)
  expect_s3_class(obj, "tbl")
  expect_false(inherits(obj, "sf"))
  # this is _not_ a _sf function
})

test_that("reverse_geo_lite() parses a successful JSON response", {
  local_mocked_bindings(api_call = function(...) {
    test_fixture("reverse-one.json")
  })

  obj <- reverse_geo_lite(40.4168, -3.7038, full_results = TRUE)

  expect_s3_class(obj, "tbl")
  expect_equal(nrow(obj), 1)
  expect_equal(obj$lat, 40.4168)
  expect_equal(obj$lon, -3.7038)
  expect_contains(names(obj), c("address", "boundingbox"))
  expect_type(obj$boundingbox, "list")
})

test_that("reverse_geo_lite() returns tabular results and forwards zoom", {
  skip_nominatim_ci()

  obj <- reverse_geo_lite(40.4207414, -3.6687109)
  expect_s3_class(obj, "tbl")
  expect_equal(nrow(obj), 1)

  expect_named(obj, c("address", "lat", "lon"))

  # Same with different zoom
  obj_zoom <- reverse_geo_lite(
    40.4207414,
    -3.6687109,
    custom_query = list(zoom = 3)
  )

  expect_s3_class(obj_zoom, "tbl")
  expect_equal(nrow(obj_zoom), 1)
  expect_false(identical(obj, obj_zoom))
})

test_that("reverse_geo_lite() handles multiple coordinates and address names", {
  skip_nominatim_ci()

  # Several coordinates
  sev <- reverse_geo_lite(
    lat = c(40.75728, 55.95335),
    long = c(-73.98586, -3.188375)
  )

  expect_equal(nrow(sev), 2)
  expect_s3_class(sev, "tbl")

  # Check opts
  obj <- reverse_geo_lite(40.4207414, -3.6687109, address = "addrs")

  expect_s3_class(obj, "tbl")
  expect_equal(nrow(obj), 1)

  expect_named(obj, c("addrs", "lat", "lon"))

  # Check opts
  obj <- reverse_geo_lite(
    40.4207414,
    -3.6687109,
    address = "addrs",
    return_coords = FALSE
  )

  expect_s3_class(obj, "tbl")
  expect_named(obj, "addrs")
})

test_that("reverse_geo_lite() controls coordinate and full-result columns", {
  skip_nominatim_ci()

  obj <- reverse_geo_lite(
    40.4207414,
    -3.6687109,
    address = "addrs",
    return_coords = FALSE,
    full_results = TRUE
  )

  expect_s3_class(obj, "tbl")
  expect_identical(names(obj)[1:3], c("addrs", "lat", "lon"))
  expect_gt(ncol(obj), 5)

  obj2 <- reverse_geo_lite(
    40.4207414,
    -3.6687109,
    address = "addrs",
    return_coords = TRUE,
    full_results = TRUE
  )

  expect_identical(obj, obj2)
})


test_that("reverse_geo_lite() unnests bounding boxes in full results", {
  skip_nominatim_ci()

  # Several coordinates
  sev <- reverse_geo_lite(
    lat = c(40.75728, 55.95335),
    long = c(-73.98586, -3.188375),
    full_results = TRUE,
    custom_query = list(extratags = TRUE)
  )

  expect_s3_class(sev, "tbl")
  expect_equal(nrow(sev), 2)

  # Classes of all cols

  colclass <- vapply(sev, class, FUN.VALUE = character(1))
  expect_contains(names(colclass), "boundingbox")
  expect_identical(colclass[["boundingbox"]], "list")

  # Rest of columns not list
  expect_no_match(
    colclass["boundingbox" != names(colclass)],
    "list",
    fixed = TRUE
  )

  # Extract
  bb_l <- sev[["boundingbox"]]
  expect_type(bb_l, "list")
  expect_length(bb_l, 2)

  # Each object
  for (i in seq_along(bb_l)) {
    lc <- bb_l[[i]]
    expect_length(lc, 4)
    expect_type(lc, "double")
  }
})

test_that("reverse_geo_lite() queries unique coordinates and restores order", {
  local_mocked_bindings(reverse_geo_lite_single = function(
    lat_cap,
    long_cap,
    address,
    ...
  ) {
    mock_reverse_tbl(lat_cap, long_cap, address)
  })

  # Dupes

  lats <- rep(c(40.75728, 55.95335), 50)
  longs <- rep(c(-73.98586, -3.188375), 50)

  expect_silent(dup <- reverse_geo_lite(lats, longs, progressbar = FALSE))

  expect_equal(nrow(dup), 100)

  nms <- unique(as.character(dup$address))
  expect_length(nms, 2)
  expect_equal(as.character(dup$address), rep(nms, 50))

  # Check deduping
  dedup <- dplyr::distinct(dup)

  expect_equal(nrow(dedup), 2)
  expect_equal(as.character(dedup$address), nms)
})

test_that("reverse_geo_lite() displays progress for multiple enabled queries", {
  local_mocked_bindings(reverse_geo_lite_single = function(
    lat_cap,
    long_cap,
    address,
    ...
  ) {
    mock_reverse_tbl(lat_cap, long_cap, address)
  })

  lat <- c(40.75728, 55.95335)
  long <- c(-73.98586, -3.188375)

  # No pbar
  expect_silent(reverse_geo_lite(lat[1], long[1]))
  expect_silent(reverse_geo_lite(lat[1], long[1], progressbar = TRUE))

  # Get a pbar
  expect_output(reverse_geo_lite(lat, long))

  # Not
  expect_silent(reverse_geo_lite(lat, long, progressbar = FALSE))
})
test_that("reverse_geo_lite() returns a typed row after API failure", {
  local_mocked_bindings(api_call = function(...) FALSE)

  expect_snapshot(
    several <- reverse_geo_lite(40.75728, -73.98, full_results = TRUE)
  )

  expect_equal(several$address, NA_character_)
})
