p1 <- as_coord2d(x = c(0, 2), y = c(0, 0))
p2 <- as_coord2d(x = c(2, 2), y = c(0, 2))
s <- as_segment2d(p1, p2 = p2)

test_that("as_segment2d() constructs a Segment2D", {
	expect_r6_class(s, "Segment2D")
	expect_r6_class(s, "Coord2D")
	expect_snapshot(print(s))
})

test_that("is_segment2d() works", {
	expect_true(is_segment2d(s))
	expect_false(is_segment2d(p1))
})

test_that("Segment2D$p1 returns first endpoints", {
	expect_r6_class(s$p1, "Coord2D")
	expect_equal(s$p1$x, c(0, 2))
	expect_equal(s$p1$y, c(0, 0))
})

test_that("Segment2D$p2 returns second endpoints", {
	expect_r6_class(s$p2, "Coord2D")
	expect_equal(s$p2$x, c(2, 2))
	expect_equal(s$p2$y, c(0, 2))
})

test_that("Segment2D$mid_point returns midpoints and caches", {
	m <- s$mid_point
	expect_r6_class(m, "Coord2D")
	expect_equal(m$x, c(1, 2))
	expect_equal(m$y, c(0, 1))
	expect_identical(s$mid_point, m)
})

test_that("length() returns number of segments", {
	expect_equal(length(s), 2L)
})

test_that("[.Segment2D subsets correctly", {
	s1 <- s[1]
	expect_r6_class(s1, "Segment2D")
	expect_equal(length(s1), 1L)
	expect_equal(s1$p1$x, 0)
	expect_equal(s1$p2$x, 2)
})

test_that("rep.Segment2D works", {
	sr <- rep(s, 2L)
	expect_equal(length(sr), 4L)
	expect_equal(sr$p1$x, c(0, 2, 0, 2))
})

test_that("as_segment2d() vec argument works", {
	vec <- as_coord2d(x = c(2, 0), y = c(0, 2))
	sv <- as_segment2d(p1, vec = vec)
	expect_equal(sv$p2$x, c(2, 2))
	expect_equal(sv$p2$y, c(0, 2))
})

test_that("as_segment2d.Polygon2D() returns edges", {
	poly <- as_polygon2d(as_coord2d(x = c(0, 1, 1, 0), y = c(0, 0, 1, 1)))
	expect_r6_class(as_segment2d(poly), "Segment2D")
	expect_equal(length(as_segment2d(poly)), 4L)
})

test_that("as_segment2d.default() errors", {
	expect_error(as_segment2d(1))
})

test_that("transformations update p1, p2, and mid_point; cache is cleared", {
	s2 <- as_segment2d(p1, p2 = p2)
	s2$translate(as_coord2d(1, 1))
	expect_equal(s2$p1$x, c(1, 3))
	expect_equal(s2$p1$y, c(1, 1))
	expect_equal(s2$p2$x, c(3, 3))
	expect_equal(s2$p2$y, c(1, 3))
	expect_equal(s2$mid_point$x, c(2, 3))
	expect_equal(s2$mid_point$y, c(1, 2))
})

test_that("rotation updates p2 and mid_point correctly", {
	s2 <- as_segment2d(
		as_coord2d(0, 0),
		p2 = as_coord2d(1, 0)
	)
	s2$rotate(degrees(90))
	expect_equal(s2$p1$x, 0, tolerance = 1e-9)
	expect_equal(s2$p1$y, 0, tolerance = 1e-9)
	expect_equal(s2$p2$x, 0, tolerance = 1e-9)
	expect_equal(s2$p2$y, 1, tolerance = 1e-9)
	expect_equal(s2$mid_point$x, 0, tolerance = 1e-9)
	expect_equal(s2$mid_point$y, 0.5, tolerance = 1e-9)
})

test_that("Polygon2D$edges returns a Segment2D of n edges", {
	poly <- as_polygon2d(as_coord2d(x = c(0, 1, 1, 0), y = c(0, 0, 1, 1)))
	e <- poly$edges
	expect_r6_class(e, "Segment2D")
	expect_equal(length(e), 4L)
	# first edge: (0,0) -> (1,0)
	expect_equal(e$p1$x[1], 0)
	expect_equal(e$p1$y[1], 0)
	expect_equal(e$p2$x[1], 1)
	expect_equal(e$p2$y[1], 0)
	# edges are cached
	expect_identical(poly$edges, e)
})

test_that("Polygon2D$edges cache is invalidated by transformation", {
	poly <- as_polygon2d(as_coord2d(x = c(0, 1, 1, 0), y = c(0, 0, 1, 1)))
	e1 <- poly$edges
	poly$translate(as_coord2d(1, 0))
	e2 <- poly$edges
	expect_equal(e2$p1$x[1], 1)
	expect_false(identical(e1, e2))
})

test_that("sort() on Segment2D orders farthest first by default via Coord2D inheritance", {
	p1 <- as_coord2d(x = c(0, 2, 1), y = c(0, 0, 2))
	p2 <- as_coord2d(x = c(2, 1, 0), y = c(0, 2, 0))
	s <- as_segment2d(p1, p2 = p2)
	s_sorted <- sort(s, alpha = degrees(45))
	depths <- painter_depth(s, scale = 1, alpha = degrees(45))
	expect_r6_class(s_sorted, "Segment2D")
	expect_equal(length(s_sorted), length(s))
	expect_equal(painter_depth(s_sorted, scale = 1, alpha = degrees(45)), sort(depths))
})

test_that("sort() on Segment2D with decreasing = TRUE gives closest first", {
	p1 <- as_coord2d(x = c(0, 2, 1), y = c(0, 0, 2))
	p2 <- as_coord2d(x = c(2, 1, 0), y = c(0, 2, 0))
	s <- as_segment2d(p1, p2 = p2)
	s_asc <- sort(s, alpha = degrees(45))
	s_desc <- sort(s, decreasing = TRUE, alpha = degrees(45))
	expect_equal(
		painter_depth(s_asc, scale = 1, alpha = degrees(45)),
		rev(painter_depth(s_desc, scale = 1, alpha = degrees(45)))
	)
})
