package wang.yaojia.webterm.testsupport

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

/** Ports iOS `FakeClockTests` — manual advance, zero real-time waiting — plus the epoch/tick shapes. */
class FakeTimeSourceTest {
    @Test
    fun markElapsesOnlyAfterManualAdvance() {
        val clock = FakeTimeSource()
        val mark = clock.markNow()
        assertEquals(Duration.ZERO, mark.elapsedNow())

        clock.advance(10.seconds) // short of a 25s deadline
        assertEquals(10.seconds, mark.elapsedNow())

        clock += 15.seconds // reach it
        assertEquals(25.seconds, mark.elapsedNow())
        assertEquals(25.seconds, clock.now)
    }

    @Test
    fun epochMillisTracksAdvanceFromBase() {
        val clock = FakeTimeSource(epochBaseMillis = 1_000L)
        assertEquals(1_000L, clock.epochMillis())

        clock.advance(30.seconds)
        assertEquals(31_000L, clock.epochMillis())
    }

    @Test
    fun cannotMoveBackwards() {
        val clock = FakeTimeSource()
        assertThrows<IllegalArgumentException> { clock.advance((-1).seconds) }
    }

    @Test
    fun tickAdvancesVirtualDelayAndReadableClockTogether() = runTest {
        val clock = FakeTimeSource()
        var fired = false
        launch {
            delay(25.seconds)
            fired = true
        }

        assertFalse(fired) // the delayed body has not run yet
        tick(clock, 25.seconds)

        assertTrue(fired) // virtual delay fired
        assertEquals(25.seconds, clock.now) // readable clock moved in lockstep
    }
}
