package de.arxsilex.maptools.converter.desktop

import de.arxsilex.maptools.converter.core.GeoBounds
import de.arxsilex.maptools.converter.core.preview.PreviewDataset
import de.arxsilex.maptools.converter.core.preview.PreviewFeatureClass
import de.arxsilex.maptools.converter.core.preview.PreviewLabel
import de.arxsilex.maptools.converter.core.preview.PreviewLabelClass
import de.arxsilex.maptools.converter.core.preview.PreviewPoint
import de.arxsilex.maptools.converter.core.preview.PreviewPolyline
import kotlin.test.Test
import kotlin.test.assertContentEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class PreviewRenderIndexTest {
    private val preview = PreviewDataset(
        bounds = GeoBounds(west = 8.0, south = 50.0, east = 9.0, north = 51.0),
        points = listOf(
            PreviewPoint(latitude = 50.85, longitude = 8.15, featureClass = PreviewFeatureClass.POI),
            PreviewPoint(latitude = 50.2, longitude = 8.8, featureClass = PreviewFeatureClass.POI),
        ),
        polylines = listOf(
            PreviewPolyline(doubleArrayOf(8.1, 50.9, 8.2, 50.8), PreviewFeatureClass.MAJOR_ROAD),
            PreviewPolyline(doubleArrayOf(8.7, 50.3, 8.9, 50.1), PreviewFeatureClass.WATER_AREA),
            PreviewPolyline(doubleArrayOf(8.4, 50.6, 8.6, 50.4), PreviewFeatureClass.PATH),
            PreviewPolyline(doubleArrayOf(8.0, 50.5, 9.0, 50.5), PreviewFeatureClass.MINOR_ROAD),
        ),
        sourceNodeCount = 0,
        sourceWayCount = 0,
        labels = listOf(
            PreviewLabel(50.85, 8.15, "Nordwest", PreviewLabelClass.POI, 60),
            PreviewLabel(50.2, 8.8, "Südost", PreviewLabelClass.POI, 60),
        ),
    )

    @Test
    fun `separates area and line drawing order`() {
        val index = PreviewRenderIndex.build(preview)

        assertContentEquals(intArrayOf(1), index.areaIndices)
        assertContentEquals(intArrayOf(0, 2, 3), index.lineIndices)
    }

    @Test
    fun `finds only geometry intersecting viewport`() {
        val index = PreviewRenderIndex.build(preview)

        assertTrue(index.intersects(0, left = 0.05f, top = 0.05f, right = 0.25f, bottom = 0.25f))
        assertFalse(index.intersects(1, left = 0.05f, top = 0.05f, right = 0.25f, bottom = 0.25f))
        assertTrue(index.intersects(2, left = 0.45f, top = 0.35f, right = 0.55f, bottom = 0.55f))
    }

    @Test
    fun `spatial queries return only viewport candidates and retain crossing geometry`() {
        val index = PreviewRenderIndex.build(preview)

        assertContentEquals(
            intArrayOf(0),
            index.queryLineIndices(left = 0.05f, top = 0.05f, right = 0.25f, bottom = 0.25f),
        )
        assertContentEquals(
            intArrayOf(1),
            index.queryAreaIndices(left = 0.65f, top = 0.65f, right = 0.95f, bottom = 0.95f),
        )
        assertContentEquals(
            intArrayOf(3),
            index.queryLineIndices(left = 0.05f, top = 0.49f, right = 0.1f, bottom = 0.51f),
        )
        assertContentEquals(
            intArrayOf(0),
            index.queryPointIndices(left = 0.05f, top = 0.05f, right = 0.25f, bottom = 0.25f),
        )
        assertContentEquals(
            intArrayOf(1),
            index.queryLabelIndices(left = 0.7f, top = 0.7f, right = 0.9f, bottom = 0.9f),
        )
    }

    @Test
    fun `screen extent supports zoom dependent level of detail`() {
        val index = PreviewRenderIndex.build(preview)

        assertFalse(
            index.hasMinimumScreenExtent(
                polylineIndex = 0,
                viewportWidth = 1f,
                viewportHeight = 1f,
                canvasWidth = 100f,
                canvasHeight = 100f,
                minimumPixels = 20f,
            ),
        )
        assertTrue(
            index.hasMinimumScreenExtent(
                polylineIndex = 0,
                viewportWidth = 0.1f,
                viewportHeight = 0.1f,
                canvasWidth = 100f,
                canvasHeight = 100f,
                minimumPixels = 20f,
            ),
        )
    }
}
