package de.arxsilex.maptools.converter.desktop

import com.sun.management.OperatingSystemMXBean
import java.lang.management.ManagementFactory

internal data class ExportResourceProfile(
    val availableProcessors: Int,
    val totalMemoryBytes: Long,
    val freeMemoryBytes: Long,
    val parallelMapsforgeOutputs: Boolean,
)

internal object ExportResourcePolicy {
    private const val GIB = 1024L * 1024L * 1024L
    private const val MIN_TOTAL_MEMORY_FOR_PARALLEL_OUTPUTS = 16L * GIB
    private const val MIN_FREE_MEMORY_FOR_PARALLEL_OUTPUTS = 10L * GIB
    private const val MIN_PROCESSORS_FOR_PARALLEL_OUTPUTS = 4

    fun detect(): ExportResourceProfile {
        val processors = Runtime.getRuntime().availableProcessors().coerceAtLeast(1)
        val operatingSystem = ManagementFactory.getOperatingSystemMXBean() as? OperatingSystemMXBean
        return from(
            availableProcessors = processors,
            totalMemoryBytes = operatingSystem?.totalMemorySize ?: 0L,
            freeMemoryBytes = operatingSystem?.freeMemorySize ?: 0L,
        )
    }

    internal fun from(
        availableProcessors: Int,
        totalMemoryBytes: Long,
        freeMemoryBytes: Long,
    ): ExportResourceProfile {
        val parallel = availableProcessors >= MIN_PROCESSORS_FOR_PARALLEL_OUTPUTS &&
            totalMemoryBytes >= MIN_TOTAL_MEMORY_FOR_PARALLEL_OUTPUTS &&
            freeMemoryBytes >= MIN_FREE_MEMORY_FOR_PARALLEL_OUTPUTS
        return ExportResourceProfile(
            availableProcessors = availableProcessors.coerceAtLeast(1),
            totalMemoryBytes = totalMemoryBytes.coerceAtLeast(0L),
            freeMemoryBytes = freeMemoryBytes.coerceAtLeast(0L),
            parallelMapsforgeOutputs = parallel,
        )
    }
}
