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

import de.arxsilex.maptools.converter.core.GeoBounds

internal const val MTCI_SCHEMA_VERSION = 1
internal const val MTCI_NODE_MAGIC = 0x4D54434E // MTCN
internal const val MTCI_WAY_MAGIC = 0x4D544357 // MTCW
internal const val MTCI_RELATION_MAGIC = 0x4D544352 // MTCR

data class MtciFileDescriptor(
    val name: String,
    val type: String,
    val shard: Int,
    val records: Long,
    val bytes: Long,
    val sha256: String,
)

data class MtciManifest(
    val schemaVersion: Int,
    val sourcePath: String,
    val sourceBytes: Long,
    val sourceLastModifiedMillis: Long,
    val sourceSha256: String,
    val sourceBounds: GeoBounds?,
    val shardCount: Int,
    val nodeCount: Long,
    val wayCount: Long,
    val relationCount: Long,
    val files: List<MtciFileDescriptor>,
) {
    fun toJson(): String = buildString {
        appendLine("{")
        appendLine("  \"schemaVersion\": $schemaVersion,")
        appendLine("  \"byteOrder\": \"BIG_ENDIAN\",")
        appendLine("  \"sourcePath\": \"${sourcePath.jsonEscaped()}\",")
        appendLine("  \"sourceBytes\": $sourceBytes,")
        appendLine("  \"sourceLastModifiedMillis\": $sourceLastModifiedMillis,")
        appendLine("  \"sourceSha256\": \"$sourceSha256\",")
        sourceBounds?.let { bounds ->
            appendLine("  \"sourceBounds\": {")
            appendLine("    \"west\": ${bounds.west},")
            appendLine("    \"south\": ${bounds.south},")
            appendLine("    \"east\": ${bounds.east},")
            appendLine("    \"north\": ${bounds.north}")
            appendLine("  },")
        } ?: appendLine("  \"sourceBounds\": null,")
        appendLine("  \"shardCount\": $shardCount,")
        appendLine("  \"nodeCount\": $nodeCount,")
        appendLine("  \"wayCount\": $wayCount,")
        appendLine("  \"relationCount\": $relationCount,")
        appendLine("  \"files\": [")
        files.forEachIndexed { index, file ->
            append("    {\"name\": \"${file.name.jsonEscaped()}\", ")
            append("\"type\": \"${file.type}\", \"shard\": ${file.shard}, ")
            append("\"records\": ${file.records}, \"bytes\": ${file.bytes}, ")
            append("\"sha256\": \"${file.sha256}\"}")
            if (index != files.lastIndex) append(',')
            appendLine()
        }
        appendLine("  ]")
        appendLine("}")
    }
}

internal fun String.jsonEscaped(): String = buildString(length) {
    this@jsonEscaped.forEach { character ->
        when (character) {
            '\\' -> append("\\\\")
            '"' -> append("\\\"")
            '\n' -> append("\\n")
            '\r' -> append("\\r")
            '\t' -> append("\\t")
            else -> append(character)
        }
    }
}
