package de.arxsilex.maptools.converter.core.mtci

import de.arxsilex.maptools.converter.core.pbf.ParallelPbfDecodeOptions
import de.arxsilex.maptools.converter.core.pbf.PbfBlockScanner
import de.arxsilex.maptools.converter.core.pbf.PbfHeaderReader
import java.nio.file.Files
import java.nio.file.Path

fun main(arguments: Array<String>) {
    require(arguments.size >= 2) {
        "Aufruf: MtciBuilderCli <quelle.osm.pbf> <ausgabeverzeichnis> [shards] [threads]"
    }
    val source = Path.of(arguments[0]).toAbsolutePath().normalize()
    val output = Path.of(arguments[1]).toAbsolutePath().normalize()
    val shardCount = arguments.getOrNull(2)?.toInt() ?: 64
    val workerCount = arguments.getOrNull(3)?.toInt()
        ?: (Runtime.getRuntime().availableProcessors() - 1).coerceIn(1, 16)
    val startedAt = System.nanoTime()
    println("MTCI phase=scan status=started source=$source bytes=${Files.size(source)}")
    val index = PbfBlockScanner.scan(source, onProgress = { progress ->
        if (progress.blocksRead % 500 == 0) {
            println("MTCI phase=scan blocks=${progress.blocksRead} bytes=${progress.bytesRead}")
        }
    })
    val bounds = PbfHeaderReader.read(source).bounds
    println("MTCI phase=shards status=started blocks=${index.dataBlockCount} shards=$shardCount threads=$workerCount")
    val manifest = MtciIntermediateBuilder.build(
        sourcePath = source,
        index = index,
        outputDirectory = output,
        sourceBounds = bounds,
        options = MtciBuildOptions(
            shardCount = shardCount,
            parallel = ParallelPbfDecodeOptions(workerCount = workerCount),
        ),
        onProgress = { progress ->
            if (progress.completedBlocks % 250 == 0 || progress.completedBlocks == progress.totalBlocks) {
                println(
                    "MTCI phase=shards blocks=${progress.completedBlocks}/${progress.totalBlocks} " +
                        "nodes=${progress.nodeCount} ways=${progress.wayCount} relations=${progress.relationCount}",
                )
            }
        },
    )
    val elapsedMillis = (System.nanoTime() - startedAt) / 1_000_000L
    val outputBytes = manifest.files.sumOf(MtciFileDescriptor::bytes) + Files.size(output.resolve("manifest.json"))
    println("MTCI status=completed elapsedMs=$elapsedMillis outputBytes=$outputBytes output=$output")
}
