package de.arxsilex.maptools.converter.core.mapsforge

import de.arxsilex.maptools.converter.core.unionOrNull
import de.arxsilex.maptools.converter.core.preview.PreviewDatasetCombiner
import de.arxsilex.maptools.converter.core.preview.PreviewRepository
import de.arxsilex.maptools.converter.core.pbf.PbfHeaderReader
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.util.Comparator
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class MapsforgeMapSourceIntegrationTest {
    @Test
    fun `optional real map source exposes metadata and preview geometry`() {
        val source = System.getenv("MAPTOOLS_TEST_MAP_SOURCE")?.takeIf(String::isNotBlank)?.let(Path::of) ?: return
        val cache = Files.createTempDirectory("maptools-map-preview-test-")
        try {
            val metadata = MapsforgeMapSource.readMetadata(source)
            val first = MapsforgeMapSource.loadOrBuildPreview(source, metadata.bounds, cache)
            val second = MapsforgeMapSource.loadOrBuildPreview(source, metadata.bounds, cache)

            assertTrue(metadata.fileVersion in 3..5)
            assertTrue(first.dataset.polylines.isNotEmpty())
            assertTrue(first.dataset.sourceWayCount > 0)
            assertTrue(second.loadedFromCache)
            assertEquals(first.dataset.polylines.size, second.dataset.polylines.size)
        } finally {
            Files.walk(cache).use { paths ->
                paths.sorted(Comparator.reverseOrder()).forEach(Files::deleteIfExists)
            }
        }
    }

    @Test
    fun `optional real map sources produce a combined preview`() {
        val sources = System.getenv("MAPTOOLS_TEST_MAP_SOURCES")
            ?.takeIf(String::isNotBlank)
            ?.split(File.pathSeparatorChar)
            ?.filter(String::isNotBlank)
            ?.map(Path::of)
            ?: return
        require(sources.size >= 2) { "MAPTOOLS_TEST_MAP_SOURCES benötigt mindestens zwei Dateipfade." }
        val cache = System.getenv("MAPTOOLS_TEST_PREVIEW_CACHE")
            ?.takeIf(String::isNotBlank)
            ?.let(Path::of)
            ?: Files.createTempDirectory("maptools-combined-map-preview-test-")
        Files.createDirectories(cache)

        val metadata = sources.map(MapsforgeMapSource::readMetadata)
        val combinedBounds = metadata.map { it.bounds }.unionOrNull()
            ?: error("Die kombinierten Bounds konnten nicht bestimmt werden.")
        val previews = sources.zip(metadata).map { (source, info) ->
            MapsforgeMapSource.loadOrBuildPreview(source, info.bounds, cache).dataset
        }
        val combined = PreviewDatasetCombiner.combine(combinedBounds, previews)

        assertTrue(combined.polylines.isNotEmpty())
        assertTrue(combined.sourceWayCount > 0)
        assertTrue(previews.all { it.polylines.isNotEmpty() })
        assertEquals(previews.sumOf { it.sourceWayCount }, combined.sourceWayCount)
    }

    @Test
    fun `optional real mapsforge and pbf sources produce a combined preview`() {
        val mapSource = System.getenv("MAPTOOLS_TEST_MAP_SOURCE")
            ?.takeIf(String::isNotBlank)
            ?.let(Path::of)
            ?: return
        val pbfSource = System.getenv("MAPTOOLS_TEST_PBF_SOURCE")
            ?.takeIf(String::isNotBlank)
            ?.let(Path::of)
            ?: return
        val cache = System.getenv("MAPTOOLS_TEST_PREVIEW_CACHE")
            ?.takeIf(String::isNotBlank)
            ?.let(Path::of)
            ?: return
        Files.createDirectories(cache)

        val mapBounds = MapsforgeMapSource.readMetadata(mapSource).bounds
        val pbfBounds = requireNotNull(PbfHeaderReader.read(pbfSource).bounds)
        val combinedBounds = listOf(mapBounds, pbfBounds).unionOrNull()
            ?: error("Die gemischten Bounds konnten nicht bestimmt werden.")
        val mapPreview = MapsforgeMapSource.loadOrBuildPreview(mapSource, mapBounds, cache).dataset
        val pbfPreview = PreviewRepository.loadOrBuild(pbfSource, pbfBounds, cache).dataset
        val combined = PreviewDatasetCombiner.combine(combinedBounds, listOf(mapPreview, pbfPreview))

        assertTrue(mapPreview.polylines.isNotEmpty())
        assertTrue(pbfPreview.polylines.isNotEmpty())
        assertTrue(combined.polylines.size >= maxOf(mapPreview.polylines.size, pbfPreview.polylines.size))
        assertEquals(mapPreview.sourceWayCount + pbfPreview.sourceWayCount, combined.sourceWayCount)
    }
}
