package space.nstart.pcp.slots_service.util

import org.junit.jupiter.api.Test
import org.locationtech.jts.geom.MultiPolygon
import org.locationtech.jts.geom.Polygon
import org.locationtech.jts.io.WKTReader
import kotlin.test.assertEquals
import kotlin.test.assertContentEquals
import kotlin.test.assertTrue

class LongitudeWrapGeometryTest {

    private val reader = WKTReader()

    @Test
    fun `normalizes prime meridian polygon into continuous longitude range`() {
        val geometry = LongitudeWrapGeometry.normalizeToContinuous360(
            reader.read("POLYGON ((-1 1, 1 1, 1 -1, -1 -1, -1 1))")
        ) as Polygon

        val xs = geometry.coordinates.map { it.x }

        assertEquals(359.0, xs.min())
        assertEquals(361.0, xs.max())
    }

    @Test
    fun `equivalent polygons around zero meridian intersect after normalization`() {
        val slotGeometry = LongitudeWrapGeometry.normalizeToContinuous360(
            reader.read("POLYGON ((359 1, 1 1, 1 -1, 359 -1, 359 1))")
        )
        val queryGeometry = LongitudeWrapGeometry.normalizeToContinuous360(
            reader.read("POLYGON ((-0.5 0.5, 0.5 0.5, 0.5 -0.5, -0.5 -0.5, -0.5 0.5))")
        )

        assertTrue(slotGeometry.intersects(queryGeometry))
    }

    @Test
    fun `builds search variants for polygons crossing zero meridian`() {
        val variants = LongitudeWrapGeometry.buildSearchVariantsWkt(
            "POLYGON ((355 1, 361 1, 361 -1, 355 -1, 355 1))"
        ).map { reader.read(it) as Polygon }

        val bounds = variants.map { listOf(it.envelopeInternal.minX, it.envelopeInternal.maxX) }

        assertContentEquals(
            listOf(
                listOf(-5.0, 1.0),
                listOf(355.0, 361.0),
                listOf(715.0, 721.0)
            ),
            bounds
        )
    }

    @Test
    fun `aligns eastern slot copy to western continuous target band`() {
        val target = reader.read("POLYGON ((355 1, 361 1, 361 -1, 355 -1, 355 1))")
        val easternSlot = reader.read("POLYGON ((0.2 0.5, 0.8 0.5, 0.8 -0.5, 0.2 -0.5, 0.2 0.5))")

        val aligned = LongitudeWrapGeometry.alignToReference(easternSlot, target) as Polygon

        assertEquals(360.2, aligned.envelopeInternal.minX)
        assertEquals(360.8, aligned.envelopeInternal.maxX)
        assertTrue(aligned.intersects(LongitudeWrapGeometry.normalizeToContinuous360(target)))
    }

    @Test
    fun `repairs wrap induced self intersection into valid multipolygon`() {
        val geometry = LongitudeWrapGeometry.normalizeToContinuous360(
            reader.read("POLYGON ((179 2, -179 2, 179 0, -179 0, 179 -2, -179 -2, 179 2))")
        )

        assertTrue(geometry is MultiPolygon)
        assertTrue(geometry.isValid)
        assertEquals(179.0, geometry.envelopeInternal.minX)
        assertEquals(181.0, geometry.envelopeInternal.maxX)
    }
}
