package de.arxsilex.maptools.converter.core.preview

import de.arxsilex.maptools.converter.core.GeoBounds
import de.arxsilex.maptools.converter.core.pbf.PbfBlockScanner
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.fileSize
import kotlin.io.path.getLastModifiedTime
import kotlin.io.path.nameWithoutExtension

data class PreviewLoadResult(
    val dataset: PreviewDataset,
    val loadedFromCache: Boolean,
    val cacheWarning: String? = null,
)

object PreviewRepository {
    fun loadOrBuild(
        source: Path,
        bounds: GeoBounds,
        cacheDirectory: Path,
        onProgress: (PreviewBuildProgress) -> Unit = {},
        isCancelled: () -> Boolean = { false },
    ): PreviewLoadResult {
        val cacheFile = cacheFile(source, cacheDirectory)
        if (Files.isRegularFile(cacheFile)) {
            runCatching { PreviewDatasetStore.read(cacheFile) }.getOrNull()?.let { cached ->
                if (PreviewDatasetStore.matchesSource(cached, source)) {
                    return PreviewLoadResult(cached.dataset, loadedFromCache = true)
                }
            }
        }
        val index = PbfBlockScanner.scan(
            source,
            onProgress = { progress ->
                onProgress(PreviewBuildProgress(PreviewBuildPhase.SCANNING, progress.blocksRead, 0))
            },
            isCancelled = isCancelled,
        )
        val dataset = PreviewDatasetBuilder.build(source, bounds, index, onProgress, isCancelled)
        val cacheWarning = PreviewDatasetStore.writeBestEffort(
            CachedPreviewDataset(index.sourceSize, index.sourceLastModifiedMillis, index.sourceSha256, dataset),
            cacheFile,
        )
        return PreviewLoadResult(
            dataset,
            loadedFromCache = false,
            cacheWarning = cacheWarning?.let { "${source.fileName}: $it" },
        )
    }

    private fun cacheFile(source: Path, cacheDirectory: Path): Path {
        val safeName = source.nameWithoutExtension.replace(Regex("[^A-Za-z0-9._-]"), "_").take(80)
        val identity = "${source.toAbsolutePath().normalize()}|${source.fileSize()}|${source.getLastModifiedTime().toMillis()}"
        val key = identity.hashCode().toUInt().toString(16)
        return cacheDirectory.resolve("$safeName-$key.mtpv")
    }
}
