package wang.yaojia.webterm.session

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

/** Ports iOS `UnreadLedgerTests` — watermark monotonicity, cap, untrusted-input guards. */
class UnreadLedgerTest {

    private val sid = "11111111-1111-4111-8111-111111111111"

    @Test
    fun aNeverSeenSessionIsUnreadWhenServerHasOutput() {
        val ledger = UnreadLedger()
        assertTrue(ledger.isUnread(sid, lastOutputAt = 1))
    }

    @Test
    fun nullLastOutputAtIsNeverUnread() {
        assertFalse(UnreadLedger().isUnread(sid, lastOutputAt = null))
    }

    @Test
    fun nonPositiveLastOutputAtIsNeverUnread() {
        val ledger = UnreadLedger()
        assertFalse(ledger.isUnread(sid, lastOutputAt = 0))
        assertFalse(ledger.isUnread(sid, lastOutputAt = -5))
    }

    @Test
    fun unreadRequiresStrictlyNewerThanWatermark() {
        val ledger = UnreadLedger().record(sid, atMs = 1_000)
        assertFalse(ledger.isUnread(sid, lastOutputAt = 999), "older is read")
        assertFalse(ledger.isUnread(sid, lastOutputAt = 1_000), "equal is read")
        assertTrue(ledger.isUnread(sid, lastOutputAt = 1_001), "newer is unread")
    }

    @Test
    fun recordIsMonotonicAndDoesNotLowerAnExistingWatermark() {
        val ledger = UnreadLedger().record(sid, atMs = 1_000).record(sid, atMs = 500)
        assertEquals(1_000L, ledger.watermarks[sid])
        assertFalse(ledger.isUnread(sid, lastOutputAt = 900))
    }

    @Test
    fun recordDoesNotMutateTheReceiver() {
        val base = UnreadLedger()
        val next = base.record(sid, atMs = 1_000)
        assertTrue(base.watermarks.isEmpty())
        assertEquals(1_000L, next.watermarks[sid])
    }

    @Test
    fun capKeepsTheNewestEntriesByWatermark() {
        // One over the cap; the single OLDEST (smallest value) must be dropped.
        val raw = buildMap {
            for (i in 0..UnreadLedger.MAX_ENTRIES) { // MAX_ENTRIES + 1 entries
                put("session-%04d".format(i), i.toLong())
            }
        }
        val ledger = UnreadLedger(raw)
        assertEquals(UnreadLedger.MAX_ENTRIES, ledger.watermarks.size)
        assertFalse(ledger.watermarks.containsKey("session-0000"), "oldest (value 0) dropped")
        assertTrue(ledger.watermarks.containsKey("session-%04d".format(UnreadLedger.MAX_ENTRIES)))
    }

    @Test
    fun equalityFoldsWatermarks() {
        val a = UnreadLedger().record(sid, atMs = 5)
        val b = UnreadLedger(mapOf(sid to 5L))
        assertEquals(a, b)
        assertEquals(a.hashCode(), b.hashCode())
    }
}
