package com.jsjdesigns.poker

import com.jsjdesigns.poker.game.Action
import com.jsjdesigns.poker.game.ActionType
import com.jsjdesigns.poker.game.HandEvent
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

class TableStatusTest {

    private fun snapshot(
        street: Street = Street.FLOP,
        phase: TableSnapshot.Phase = TableSnapshot.Phase.BETTING,
        toAct: Int? = null,
        lastAction: HandEvent? = null,
    ) = TableSnapshot(
        handNumber = 3,
        street = street,
        phase = phase,
        board = emptyList(),
        pot = 20,
        currentBet = 4,
        minRaiseSize = 2,
        button = 0,
        seats = listOf(
            seat(0, "Jay"),
            seat(1, "Ada"),
        ),
        toAct = toAct,
        toActToken = toAct?.toLong(),
        lastAction = lastAction,
    )

    private fun seat(index: Int, name: String) = SeatSnapshot(
        index = index,
        name = name,
        stack = 200,
        committedThisRound = 0,
        committedThisHand = 0,
        folded = false,
        allIn = false,
        hole = null,
        revealed = false,
        isButton = index == 0,
    )

    private fun event(
        seat: Int = 1,
        name: String = "Ada",
        action: Action,
    ) = HandEvent(Street.FLOP, seat, name, action)

    @Test
    fun `current actor carries the preceding same-street action`() {
        val previous = event(action = Action(ActionType.RAISE, 12))

        assertEquals(
            TableStatus("Your turn  •  Ada raised to 12", TableStatusTone.ACCENT),
            tableStatus(snapshot(toAct = HERO_SEAT, lastAction = previous)),
        )
        val heroCall = event(
            seat = HERO_SEAT,
            name = "Jay",
            action = Action(ActionType.CALL, 6),
        )
        assertEquals(
            TableStatus("You called 6  •  Ada is thinking…", TableStatusTone.NORMAL),
            tableStatus(snapshot(toAct = 1, lastAction = heroCall)),
        )
    }

    @Test
    fun `actions use honest past-tense amounts and identify hero by seat`() {
        val cases = listOf(
            Action(ActionType.FOLD) to "Ada folded",
            Action(ActionType.CHECK) to "Ada checked",
            Action(ActionType.CALL, 6) to "Ada called 6",
            Action(ActionType.BET, 8) to "Ada bet 8",
            Action(ActionType.RAISE, 20) to "Ada raised to 20",
        )
        for ((action, expected) in cases) {
            assertEquals(expected, tableStatus(snapshot(lastAction = event(action = action)))?.text)
        }

        val hero = event(seat = HERO_SEAT, name = "Jay", action = Action(ActionType.FOLD))
        assertEquals("You folded", tableStatus(snapshot(lastAction = hero))?.text)
    }

    @Test
    fun `new cards outrank a retained action from the prior street`() {
        val staleCall = event(action = Action(ActionType.CALL, 4))

        assertEquals(
            "Cards dealt",
            tableStatus(
                snapshot(
                    street = Street.PREFLOP,
                    phase = TableSnapshot.Phase.DEALT,
                    lastAction = staleCall,
                ),
            )?.text,
        )
        assertEquals(
            "Flop dealt",
            tableStatus(
                snapshot(
                    street = Street.FLOP,
                    phase = TableSnapshot.Phase.STREET_COMPLETE,
                    lastAction = staleCall,
                ),
            )?.text,
        )

        assertEquals(
            "Ada is thinking…",
            tableStatus(
                snapshot(
                    street = Street.TURN,
                    phase = TableSnapshot.Phase.BETTING,
                    toAct = 1,
                    lastAction = staleCall,
                ),
            )?.text,
        )
    }

    @Test
    fun `terminal frames leave the explanation to the hand summary`() {
        assertNull(tableStatus(snapshot(phase = TableSnapshot.Phase.SHOWDOWN)))
        assertNull(tableStatus(snapshot(phase = TableSnapshot.Phase.COMPLETE)))
    }
}
