package de.arxsilex.maptools.converter.worker

import de.arxsilex.maptools.converter.core.GeoBounds
import de.arxsilex.maptools.converter.core.GeoRectangleRegion
import de.arxsilex.maptools.converter.core.GeoSelectionRegion
import java.nio.file.Files
import java.nio.file.Path

data class CropRequest(
    val input: Path,
    val output: Path,
    val bounds: GeoBounds,
    val cacheDirectory: Path,
    val temporaryDirectory: Path,
    val areas: List<GeoSelectionRegion> = listOf(GeoRectangleRegion(bounds)),
) {
    init {
        require(Files.isRegularFile(input)) { "Eingabedatei nicht gefunden: $input" }
        require(input.toAbsolutePath().normalize() != output.toAbsolutePath().normalize()) {
            "Ein- und Ausgabedatei dürfen nicht identisch sein."
        }
        require(areas.isNotEmpty()) { "Mindestens ein Auswahlbereich ist erforderlich." }
        require(SelectionBoundsCodec.envelope(areas) == bounds) { "Die Auswahlhülle stimmt nicht mit den Teilbereichen überein." }
    }

    fun osmosisArguments(temporaryOutput: Path): Array<String> {
        require(areas.size == 1 && areas.single() is GeoRectangleRegion) {
            "Der Osmosis-Einzelzuschnitt unterstützt nur ein Rechteck."
        }
        return arrayOf(
        "--read-pbf",
        "file=${input.toAbsolutePath().normalize()}",
        "--bounding-box",
        "left=${bounds.west}",
        "right=${bounds.east}",
        "top=${bounds.north}",
        "bottom=${bounds.south}",
        "completeWays=yes",
        "completeRelations=yes",
        "clipIncompleteEntities=false",
        "--write-pbf",
        "file=${temporaryOutput.toAbsolutePath().normalize()}",
        "omitmetadata=false",
        "usedense=true",
        "compress=deflate",
        )
    }

    companion object {
        fun parse(arguments: Array<String>): CropRequest {
            require(arguments.firstOrNull() == "crop") { "Erwarteter Worker-Befehl: crop" }
            val values = arguments.drop(1).chunked(2).associate { pair ->
                require(pair.size == 2 && pair[0].startsWith("--")) { "Ungültige Worker-Argumente." }
                pair[0].removePrefix("--") to pair[1]
            }
            fun required(name: String): String = values[name] ?: error("Worker-Argument --$name fehlt.")
            val output = Path.of(required("output")).toAbsolutePath().normalize()
            val areas = SelectionBoundsCodec.fromArguments(values)
            return CropRequest(
                input = Path.of(required("input")).toAbsolutePath().normalize(),
                output = output,
                bounds = SelectionBoundsCodec.envelope(areas),
                cacheDirectory = values["cache-dir"]?.let(Path::of)?.toAbsolutePath()?.normalize()
                    ?: output.parent.resolve("cache"),
                temporaryDirectory = values["temp-dir"]?.let(Path::of)?.toAbsolutePath()?.normalize()
                    ?: output.parent.resolve(".maptools-temp"),
                areas = areas,
            )
        }
    }
}
