package wang.yaojia.webterm.session

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
import wang.yaojia.webterm.wire.WireConstants
import kotlin.time.Duration.Companion.seconds

class SessionEventTest {

    @Test
    fun `connection wraps a lifecycle state by value`() {
        val event: SessionEvent = Connection(ConnectionState.Connected)
        assertEquals(Connection(ConnectionState.Connected), event)
        assertNotEquals(Connection(ConnectionState.Connecting), event)
    }

    @Test
    fun `reconnecting carries the attempt number and next delay`() {
        val state = ConnectionState.Reconnecting(attempt = 3, next = 8.seconds)
        assertEquals(3, state.attempt)
        assertEquals(8.seconds, state.next)
    }

    @Test
    fun `failed is the non-retryable terminal state carrying its reason`() {
        val state = ConnectionState.Failed(FailureReason.REPLAY_TOO_LARGE)
        assertEquals(FailureReason.REPLAY_TOO_LARGE, state.reason)
    }

    @Test
    fun `exited defaults its reason to null and surfaces the spawn-failure code`() {
        assertNull(Exited(code = 0).reason)

        val spawnFailure = Exited(code = WireConstants.SPAWN_FAILED_EXIT_CODE, reason = "spawn failed")
        assertEquals(-1, spawnFailure.code)
        assertEquals("spawn failed", spawnFailure.reason)
    }

    @Test
    fun `adopted and output carry their payloads by value`() {
        assertEquals(Adopted("id-1"), Adopted("id-1"))
        assertNotEquals(Adopted("id-1"), Adopted("id-2"))

        assertEquals(Output("bytes"), Output("bytes"))
        assertNotEquals(Output("a"), Output("b"))
    }

    @Test
    fun `every A5 lifecycle subtype is a SessionEvent`() {
        val events: List<SessionEvent> = listOf(
            Connection(ConnectionState.Closed),
            Adopted("id"),
            Output("data"),
            Exited(code = 0),
        )
        assertEquals(4, events.size)
    }
}
