package de.arxsilex.maptools.converter.desktop

import kotlin.test.Test
import kotlin.test.assertContains
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class ExportProgressTrackerTest {
    @Test
    fun `tracks elevation as an independent export stage`() {
        val updates = mutableListOf<ExportProgressSnapshot>()
        val tracker = ExportProgressTracker(
            plan = ExportProgressPlan.create(
                mapsforgeSourceCount = 0,
                preparesMapData = false,
                writesMap = false,
                writesPoi = false,
                writesElevation = true,
            ),
            strings = LocalizationCatalog.strings(AppLanguage.ENGLISH),
            nanoTime = { 0L },
            onUpdate = updates::add,
        )

        val listener = tracker.listener("elevation")
        listener("MTC-WORKER phase=elevation status=running current=50 total=100")

        assertEquals("elevation", updates.last().phase)
        assertTrue(updates.last().progress > 0f)
    }

    @Test
    fun `mapsforge zoom interval percentages remain monotonic whole job progress`() {
        var now = 0L
        val snapshots = mutableListOf<ExportProgressSnapshot>()
        val tracker = ExportProgressTracker(
            plan = ExportProgressPlan.create(
                mapsforgeSourceCount = 1,
                preparesMapData = true,
                writesMap = true,
                writesPoi = true,
            ),
            strings = LocalizationCatalog.strings(AppLanguage.GERMAN),
            nanoTime = { now },
            onUpdate = snapshots::add,
        )

        val source = tracker.listener("source-0")
        val prepare = tracker.listener("prepare")
        val map = tracker.listener("map")
        source("MTC-WORKER phase=mapsforge-source status=completed")
        prepare("MTC-WORKER phase=combine-merge status=completed")
        now = 15L * 60L * 1_000_000_000L
        map("MTC-WORKER phase=mapsforge-map status=started processor=hd")
        map("INFORMATION: start writing file...")
        map("INFORMATION: written 30% of sub file for zoom interval 2 (10,8,11)")
        val secondIntervalProgress = snapshots.last().progress
        map("INFORMATION: written 30% of sub file for zoom interval 3 (14,12,21)")
        val thirdIntervalProgress = snapshots.last().progress

        assertTrue(snapshots.zipWithNext().all { (before, after) -> after.progress >= before.progress })
        assertTrue(secondIntervalProgress > 0.50f, "completed preparation must be part of overall progress")
        assertTrue(thirdIntervalProgress > secondIntervalProgress, "later zoom intervals must advance progress")
        assertTrue(thirdIntervalProgress < 0.90f, "POI generation and validation are still pending")
        assertContains(snapshots.last().message, "Gesamtzeit 15:00")
    }

    @Test
    fun `mapsforge source object totals advance their own stage`() {
        val snapshots = mutableListOf<ExportProgressSnapshot>()
        val tracker = ExportProgressTracker(
            plan = ExportProgressPlan.create(
                mapsforgeSourceCount = 1,
                preparesMapData = false,
                writesMap = true,
                writesPoi = false,
            ),
            strings = LocalizationCatalog.strings(AppLanguage.GERMAN),
            onUpdate = snapshots::add,
        )
        val source = tracker.listener("source-0")

        source("MTC-WORKER phase=mapsforge-source status=running writePhase=WAYS current=50 total=100 blocks=4")
        val halfway = snapshots.last().progress
        source("MTC-WORKER phase=mapsforge-source status=running writePhase=WAYS current=100 total=100 blocks=8")

        assertTrue(snapshots.last().progress > halfway)
        assertContains(snapshots.last().message, "100")
    }

    @Test
    fun `parallel map and poi updates contribute independently`() {
        val snapshots = mutableListOf<ExportProgressSnapshot>()
        val tracker = ExportProgressTracker(
            plan = ExportProgressPlan.create(
                mapsforgeSourceCount = 0,
                preparesMapData = false,
                writesMap = true,
                writesPoi = true,
            ),
            strings = LocalizationCatalog.strings(AppLanguage.ENGLISH),
            onUpdate = snapshots::add,
        )
        val map = tracker.listener("map")
        val poi = tracker.listener("poi")

        map("MTC-WORKER phase=mapsforge-map status=completed")
        val mapComplete = snapshots.last().progress
        poi("MTC-WORKER phase=mapsforge-poi status=completed")

        assertTrue(snapshots.last().progress > mapComplete)
        assertTrue(snapshots.last().progress < 1f, "validation still has to run")
        tracker.complete("validate")
        assertEquals(1f, snapshots.last().progress)
    }
}
