package ca.ksamad.encore.mpd

import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout
import org.junit.Assert.assertEquals
import org.junit.Assume.assumeTrue
import org.junit.Test

/**
 * Live end-to-end test of [MpdClient] against a real server (skipped unless `MPD_HOST` is set — see
 * [MpdServerIntegrationTest]).
 *
 * The interesting part is the idle round-trip: we change the volume on the **command** connection
 * and then wait for that change to arrive back through the **idle** connection into the `status`
 * flow — proving the two-connection push architecture actually works. The volume nudge is reverted
 * afterwards.
 */
class MpdClientIntegrationTest {
    private val host = System.getenv("MPD_HOST")
    private val port = System.getenv("MPD_PORT")?.toIntOrNull() ?: MpdConnection.DEFAULT_PORT
    private val password = System.getenv("MPD_PASSWORD")

    @Test
    fun clientConnectsAndReceivesIdlePushUpdates() = runBlocking {
        assumeTrue("set MPD_HOST to run the live MPD client test", host != null)
        val host = host!!

        val client = MpdClient()
        try {
            println("=== MpdClient live test: $host:$port ===")
            client.connect(host, port, password)
            assertEquals(MpdConnectionState.Connected, client.connectionState.value)

            // Initial state, primed during connect().
            val initial = withTimeout(5_000) { client.status.first { it != null } }!!
            println(
                "connected. state=${initial.state} volume=${initial.volume} song='${client.currentSong.value?.title}'"
            )

            val startVolume = initial.volume
            if (startVolume == null) {
                println("volume unavailable (output closed) — skipping idle-push volume demo")
                return@runBlocking
            }

            // Nudge the volume on the command connection...
            val nudged = if (startVolume >= 3) startVolume - 3 else startVolume + 3
            println("setting volume $startVolume -> $nudged on the command connection...")
            client.setVolume(nudged)

            // ...and wait for the change to come back via the idle connection.
            val observed =
                withTimeout(5_000) {
                    client.status.first { it?.volume == nudged }
                }!!
            println("idle push observed: status flow now reports volume=${observed.volume} ✔")
            assertEquals(nudged, observed.volume)

            // Restore the original volume and confirm that round-trips too.
            client.setVolume(startVolume)
            withTimeout(5_000) { client.status.first { it?.volume == startVolume } }
            println("restored volume to $startVolume ✔")
        } finally {
            client.disconnect()
            println("disconnected. state=${client.connectionState.value}")
            println("=== OK ===")
        }
    }
}
