package com.jsjdesigns.poker

import com.jsjdesigns.poker.game.DecisionOffer
import com.jsjdesigns.poker.game.SeatSnapshot
import com.jsjdesigns.poker.game.Street
import com.jsjdesigns.poker.game.TableSnapshot
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test

/**
 * The action bar must never be rendered against a table it does not belong to.
 */
class LiveOfferTest {

    private fun snapshot(
        handNumber: Int = 1,
        street: Street = Street.FLOP,
        toAct: Int? = HERO_SEAT,
        toActToken: Long? = 7L,
    ) = TableSnapshot(
        handNumber = handNumber,
        street = street,
        phase = TableSnapshot.Phase.BETTING,
        board = emptyList(),
        pot = 40,
        currentBet = 10,
        minRaiseSize = 10,
        button = 0,
        seats = listOf(
            SeatSnapshot(0, "You", 500, 0, 0, false, false, listOf(0, 1), false, true),
        ),
        toAct = toAct,
        toActToken = toActToken,
        lastAction = null,
    )

    private fun offer(token: Long = 7L, handNumber: Int = 1, street: Street = Street.FLOP) =
        DecisionOffer(
            token = token,
            handNumber = handNumber,
            street = street,
            seat = HERO_SEAT,
            hole = listOf(0, 1),
            board = emptyList(),
            pot = 40,
            toCall = 10,
            minRaiseTo = 20,
            maxRaiseTo = 500,
            stack = 500,
            canCheck = false,
            canRaise = true,
            activeOpponents = 1,
            seatsActingAfter = 0,
            bigBlind = 2,
            eligiblePot = 40,
            currentBet = 10,
        )

    @Test
    fun `an offer matching the displayed decision is live`() {
        val state = UiState(snapshot = snapshot(toActToken = 7L))
        assertEquals(7L, state.liveOffer(offer(token = 7L))?.token)
    }

    @Test
    fun `an offer from a later decision is withheld until its frame is shown`() {
        // The engine has moved on; the board on screen is still the older one.
        val state = UiState(snapshot = snapshot(toActToken = 7L))
        assertNull(
            "showing a newer offer against a stale table is what made actions look wrong",
            state.liveOffer(offer(token = 8L)),
        )
    }

    /**
     * Hand+street matching was not enough: a player can face two decisions on the
     * same street, e.g. bet, get raised, act again.
     */
    @Test
    fun `two decisions on the same street are distinguished`() {
        val state = UiState(snapshot = snapshot(handNumber = 1, street = Street.FLOP, toActToken = 12L))
        assertNull(
            "same hand and street, different decision — must not match",
            state.liveOffer(offer(token = 11L, handNumber = 1, street = Street.FLOP)),
        )
        assertEquals(12L, state.liveOffer(offer(token = 12L, handNumber = 1, street = Street.FLOP))?.token)
    }

    @Test
    fun `nothing is live when no one is being asked to act`() {
        val state = UiState(snapshot = snapshot(toAct = null, toActToken = null))
        assertNull(state.liveOffer(offer()))
    }

    @Test
    fun `nothing is live before the first frame arrives`() {
        assertNull(UiState(snapshot = null).liveOffer(offer()))
    }

    @Test
    fun `no offer means no action bar`() {
        assertNull(UiState(snapshot = snapshot()).liveOffer(null))
    }
}
