package com.fabledsword.minstrel.player

import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class RemotePlayerStateTest {

    @Test
    fun `starts in idle state`() {
        val state = RemotePlayerState()
        assertFalse(state.isPlaying)
        assertEquals(0L, state.positionMs)
        assertEquals(0L, state.durationMs)
    }

    @Test
    fun `applyPositionInfo updates position, duration, and trackNumber`() {
        val state = RemotePlayerState()
        state.applyPositionInfo(
            positionMs = 65_000L, durationMs = 210_000L, trackUri = "x", trackNumber = 3,
        )
        assertEquals(65_000L, state.positionMs)
        assertEquals(210_000L, state.durationMs)
        assertEquals("x", state.currentTrackUri)
        assertEquals(3, state.trackNumber)
    }

    @Test
    fun `applyTransportPlaying flips isPlaying true`() {
        val state = RemotePlayerState()
        state.applyTransportPlaying()
        assertTrue(state.isPlaying)
    }

    @Test
    fun `applyTransportPaused flips isPlaying false`() {
        val state = RemotePlayerState().apply { applyTransportPlaying() }
        state.applyTransportPaused()
        assertFalse(state.isPlaying)
    }

    @Test
    fun `applyError resets to idle and records error`() {
        val state = RemotePlayerState().apply { applyTransportPlaying() }
        val ex = RuntimeException("disconnected")
        state.applyError(ex)
        assertFalse(state.isPlaying)
        assertEquals(ex, state.lastError)
    }

    @Test
    fun `recordPollFailure trips after threshold`() {
        val state = RemotePlayerState()
        // Threshold is 30 -- tolerate ~30s of screen-off WiFi sleep before
        // declaring the remote dropped. Pre-threshold calls all return false.
        repeat(DROP_THRESHOLD - 1) {
            assertFalse(state.recordPollFailure())
        }
        assertTrue(state.recordPollFailure())
    }

    @Test
    fun `recordPollSuccess clears the failure counter`() {
        val state = RemotePlayerState()
        repeat(DROP_THRESHOLD - 1) { state.recordPollFailure() }
        state.recordPollSuccess()
        assertFalse(state.recordPollFailure())
    }

    @Test
    fun `play intent survives a SOAP error so a failed play can resume locally`() {
        val state = RemotePlayerState()
        state.setPlayIntent(true)
        state.applyError(RuntimeException("connect timeout"))
        // isPlaying is cleared by the error, but the operator's intent persists.
        assertFalse(state.isPlaying)
        assertTrue(state.lastPlayIntent)
    }

    @Test
    fun `pausing clears play intent`() {
        val state = RemotePlayerState()
        state.setPlayIntent(true)
        state.setPlayIntent(false)
        assertFalse(state.lastPlayIntent)
    }

    @Test
    fun `reset clears play intent`() {
        val state = RemotePlayerState()
        state.setPlayIntent(true)
        state.reset()
        assertFalse(state.lastPlayIntent)
    }

    private companion object {
        const val DROP_THRESHOLD = 30
    }
}
