package ch.dissem.yaep.ui.common

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.SkikoComposeUiTest
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.runSkikoComposeUiTest
import androidx.compose.ui.unit.dp
import ch.dissem.yaep.domain.Game
import ch.dissem.yaep.domain.UnsolvablePuzzleException
import ch.dissem.yaep.ui.common.focus.FocusFollowingSelectionManager
import ch.tutteli.atrium.api.fluent.en_GB.toEqual
import ch.tutteli.atrium.api.verbs.expect
import kotlin.test.Test
import kotlin.test.fail

@OptIn(ExperimentalTestApi::class)
class AppTest {
    val game = createGame()
    var resetCluesBeacon by mutableStateOf(Any())

    @Test
    fun ensure_app_can_be_rendered_on_1920x1080_and_can_be_solved() = ensure_app_can_be_rendered_on(
        Size(1920f, 1080f)
    ) {
        val clues = game.clues
        val grid = game.grid
        var removedOptions: Boolean
        do {
            removedOptions = false
            try {
                clues.forEach { clue ->
                    val optionsRemoved = clue.removeForbiddenOptions(grid)
                    removedOptions = optionsRemoved || removedOptions
                    if (optionsRemoved) {
                        resetCluesBeacon = Any()
                    }
                }
            } catch (_: UnsolvablePuzzleException) {
                fail("puzzle can't be solved")
            }
            grid.cleanupOptions()
            resetCluesBeacon = Any()
        } while (removedOptions)

        expect(game.isSolved).toEqual(true)
        onNodeWithTag("EndOfGame.solved_time").assertExists("End of Game must be shown when puzzle is solved")
    }

    @Test
    fun ensure_app_can_be_rendered_on_1080x1920() = ensure_app_can_be_rendered_on(
        Size(1080f, 1920f)
    )

    @Test
    fun ensure_app_can_be_rendered_on_800x600() = ensure_app_can_be_rendered_on(
        Size(800f, 600f)
    )

    @Test
    fun ensure_app_can_be_rendered_on_600x800() = ensure_app_can_be_rendered_on(
        Size(600f, 800f)
    )

    fun ensure_app_can_be_rendered_on(
        screenSize: Size,
        block: suspend SkikoComposeUiTest.() -> Unit = {}
    ) = runSkikoComposeUiTest(size = screenSize) {
        setContent {
            App(
                modifier = Modifier.fillMaxSize(),
                rootSelectionManager = FocusFollowingSelectionManager,
                spacing = 8.dp,
                game = game,
                onNewGame = { },
                resetCluesBeacon = resetCluesBeacon
            )
        }
        block()
    }

    private fun createGame(): Game = Game.parse(
        """
        * MATE is between the neighbours TEACHER and GOAT to both sides
        * SCIENTIST is between the neighbours SPAIN and FIREFIGHTER to both sides
        * TEA is left of COFFEE
        * ZEBRA is between the neighbours LEMON and CAKE to both sides
        * CUPCAKE is left of GOAT
        * ROCK_STAR is left of SPAIN
        * PEAR is at position 1
        * CHOCOLATE is between the neighbours TEA and MILK to both sides
        * FARMER is between the neighbours PEAR and CHERRIES to both sides
        * SWITZERLAND is between the neighbours JAPAN and DOG to both sides
        * MANGO and SPAIN are in the same column
        * SPAIN is next to SNAIL
        * CANADA is next to PIE
        * JAPAN is between the neighbours SWITZERLAND and CAKE to both sides
        * FIREFIGHTER is between the neighbours GOAT and STRAWBERRY to both sides
        * UKRAINE is between the neighbours ANT and BEVERAGE to both sides
        * CHOCOLATE and SWITZERLAND are in the same column
        * PEAR is left of COFFEE
        * JAPAN is between the neighbours CAKE and COFFEE to both sides
        * BEVERAGE is between the neighbours CUSTARD and UKRAINE to both sides
        * CANADA and CAKE are in the same column
        """.trimIndent()
    )

}