package wang.yaojia.webterm.hostregistry

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotSame
import org.junit.jupiter.api.Test
import wang.yaojia.webterm.wire.HostEndpoint

/**
 * The pure list transforms shared by every [HostStore] impl (DRY). They must be
 * immutable: return a NEW list, never mutate the receiver — the invariant the whole
 * store contract rests on. Mirrors the iOS `extension [Host]` behaviour.
 */
class HostStoreTransformsTest {

    private fun host(id: String, name: String = "host-$id", baseUrl: String = "http://10.0.0.$id:3000"): Host =
        Host(id = id, name = name, endpoint = requireNotNull(HostEndpoint.fromBaseUrl(baseUrl)))

    @Test
    fun `upserting a new id appends to the end`() {
        // Arrange
        val a = host("1")
        val b = host("2")

        // Act
        val result = listOf(a).upserting(b)

        // Assert
        assertEquals(listOf(a, b), result)
    }

    @Test
    fun `upserting an existing id replaces in place, preserving position`() {
        // Arrange
        val a = host("1")
        val b = host("2")
        val c = host("3")
        val renamedB = host("2", name = "renamed")

        // Act
        val result = listOf(a, b, c).upserting(renamedB)

        // Assert — same length, same order, middle element replaced
        assertEquals(listOf(a, renamedB, c), result)
        assertEquals("renamed", result[1].name)
    }

    @Test
    fun `upserting does not mutate the original list`() {
        // Arrange
        val original = listOf(host("1"))

        // Act
        val result = original.upserting(host("2"))

        // Assert — original untouched; a new instance was returned
        assertEquals(1, original.size)
        assertEquals(2, result.size)
        assertNotSame(original, result)
    }

    @Test
    fun `removing an existing id drops exactly that entry`() {
        // Arrange
        val a = host("1")
        val b = host("2")

        // Act
        val result = listOf(a, b).removing("1")

        // Assert
        assertEquals(listOf(b), result)
    }

    @Test
    fun `removing an unknown id is a no-op returning the same contents`() {
        // Arrange
        val original = listOf(host("1"), host("2"))

        // Act
        val result = original.removing("nope")

        // Assert — contents unchanged, original list not mutated
        assertEquals(original, result)
        assertEquals(2, original.size)
    }
}
