test_that("wk_orient() works", {
  # ccw to ccw
  expect_identical(
    wk_orient(
      wkt("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0), (0.2 0.2, 0.2 0.8, 0.8 0.8, 0.8 0.2, 0.2 0.2))"),
      direction = wk_counterclockwise()
    ),
    wkt("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0), (0.2 0.2, 0.2 0.8, 0.8 0.8, 0.8 0.2, 0.2 0.2))")
  )

  # ccw to cw
  expect_identical(
    wk_orient(
      wkt("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0), (0.2 0.2, 0.2 0.8, 0.8 0.8, 0.8 0.2, 0.2 0.2))"),
      direction = wk_clockwise()
    ),
    wkt("POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0), (0.2 0.2, 0.8 0.2, 0.8 0.8, 0.2 0.8, 0.2 0.2))")
  )

  # inconsistent to ccw
  expect_identical(
    wk_orient(
      wkt("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0), (0.2 0.2, 0.8 0.2, 0.8 0.8, 0.2 0.8, 0.2 0.2))"),
      direction = wk_counterclockwise()
    ),
    wkt("POLYGON ((0 0, 1 0, 1 1, 0 1, 0 0), (0.2 0.2, 0.2 0.8, 0.8 0.8, 0.8 0.2, 0.2 0.2))")
  )

  # a collection
  expect_identical(
    wk_orient(
      wkt(c("MULTIPOLYGON (((1 1, 2 1, 1 2, 1 1)), ((0 -1, 0 1, 1 0, 0 -1)))")),
      direction = wk_clockwise()
    ),
    wkt(c("MULTIPOLYGON (((1 1, 1 2, 2 1, 1 1)), ((0 -1, 0 1, 1 0, 0 -1)))"))
  )

  # xyz
  expect_identical(
    wk_orient(
      wkt("POLYGON Z ((1 1 5, 2 4 3, 4 3 2, 1 1 5))"),
      direction = wk_clockwise()
    ),
    wkt("POLYGON Z ((1 1 5, 2 4 3, 4 3 2, 1 1 5))")
  )

  # xyzm
  expect_identical(
    wk_orient(
      wkt("POLYGON ZM ((1 1 5 1, 2 4 3 2, 4 3 2 3, 1 1 5 1))"),
      direction = wk_counterclockwise()
    ),
    wkt("POLYGON ZM ((1 1 5 1, 4 3 2 3, 2 4 3 2, 1 1 5 1))")
  )
})

test_that("wk_orient() works for nested collections", {
  expect_identical(
    wk_orient(
      wkt("GEOMETRYCOLLECTION (GEOMETRYCOLLECTION (MULTIPOLYGON (((0 0, 1 0, 0 1, 0 0)))))"),
      direction = wk_clockwise()
    ),
    wkt("GEOMETRYCOLLECTION (GEOMETRYCOLLECTION (MULTIPOLYGON (((0 0, 0 1, 1 0, 0 0)))))")
  )
})

test_that("wk_orient() skips non-polygons", {
  expect_identical(
    wk_orient(
      wkt(c("MULTIPOINT ((0 1))", "LINESTRING (1 1, 2 2, 3 3)", "POLYGON ((0 0, 0 1, 1 0, 0 0))")),
      direction = wk_counterclockwise()
    ),
    wkt(c("MULTIPOINT ((0 1))", "LINESTRING (1 1, 2 2, 3 3)", "POLYGON ((0 0, 1 0, 0 1, 0 0))"))
  )

  expect_identical(
    wk_orient(
      xyzm(1:10, 11:20, -1, -2)
    ),
    xyzm(1:10, 11:20, -1, -2)
  )
})

test_that("wk_orient() skips empty geometries", {
  # null feature
  expect_identical(
    wk_orient(
      wkt(NA)
    ),
    wkt(NA)
  )

  # empty vector
  expect_identical(
    wk_orient(
      wkt()
    ),
    wkt()
  )

  expect_identical(
    wk_orient(
      wkt(c("POINT EMPTY", "LINESTRING EMPTY", "POLYGON EMPTY"))
    ),
    wkt(c("POINT EMPTY", "LINESTRING EMPTY", "POLYGON EMPTY"))
  )

  expect_identical(
    wk_orient(
      wkt(c("MULTIPOINT EMPTY", "MULTILINESTRING EMPTY", "MULTIPOLYGON EMPTY", "GEOMETRYCOLLECTION EMPTY"))
    ),
    wkt(c("MULTIPOINT EMPTY", "MULTILINESTRING EMPTY", "MULTIPOLYGON EMPTY", "GEOMETRYCOLLECTION EMPTY"))
  )
})

test_that("wk_orient() skips zero-area polygons", {
  # zero area
  expect_identical(
    wk_orient(
      wkt("POLYGON ((1 1, 2 2, 3 3, 1 1))"),
      wk_clockwise()
    ),
    wkt("POLYGON ((1 1, 2 2, 3 3, 1 1))")
  )

  expect_identical(
    wk_orient(
      wkt("POLYGON ((1 1, 2 2, 3 3, 1 1))"),
      wk_counterclockwise()
    ),
    wkt("POLYGON ((1 1, 2 2, 3 3, 1 1))")
  )
})

test_that("wk_orient() handles invalid polygons", {
  # invalid polygon, no coordinates
  expect_identical(
    wk_handle(
      wkt("POLYGON (EMPTY)"),
      # wkt writer will throw here
      wk_orient_filter(
        wkb_writer()
      )
    ),
    wk_handle(
      wkt("POLYGON (EMPTY)"),
      wkb_writer()
    )
  )

  # invalid polygon, no area
  expect_identical(
    wk_orient(
      wkt("POLYGON ((0 0, 1 1))")
    ),
    wkt("POLYGON ((0 0, 1 1))")
  )
})

test_that("wk_orient() preserves attributes", {
  expect_identical(
    wk_orient(
      wkt("POLYGON ((0 0, 0 0.5, 0.5 0.5, 0.5 0, 0 0))", crs = wk_crs_longlat(), geodesic = TRUE),
      direction = wk_clockwise()
    ),
    wkt("POLYGON ((0 0, 0 0.5, 0.5 0.5, 0.5 0, 0 0))", crs = wk_crs_longlat(), geodesic = TRUE)
  )

  expect_identical(
    wk_orient(
      wkt("POLYGON ((0 0, 0 0.5, 0.5 0.5, 0.5 0, 0 0))", crs = wk_crs_longlat(), geodesic = TRUE),
      direction = wk_counterclockwise()
    ),
    wkt("POLYGON ((0 0, 0.5 0, 0.5 0.5, 0 0.5, 0 0))", crs = wk_crs_longlat(), geodesic = TRUE)
  )
})
