package com.ponzischeme89.memby.ui

import androidx.compose.runtime.Composable
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onRoot
import com.github.takahirom.roborazzi.captureRoboImage
import com.ponzischeme89.memby.ui.setup.SignInContent
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.annotation.GraphicsMode

/**
 * Every screen a new television shows before it reaches the launcher, to
 * `build/screenshots/onboarding/`.
 *
 * ```powershell
 * .\gradlew.bat :app:testDebugUnitTest --tests "*OnboardingScreenshotTest"
 * ```
 *
 * This sequence is the one nobody on the team sees twice — it happens once per TV, usually
 * while somebody else is setting it up in another room — and it is the sequence that decides
 * whether that TV can ever update itself. Being able to look at it without reinstalling the
 * app on hardware is the whole point.
 *
 * The composables here take their state as parameters, which is what allows this: none of
 * them reaches for `ServiceLocator`, so there is no repository, no gateway and no session
 * behind any of these frames.
 */
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(sdk = [34], qualifiers = "w960dp-h540dp-television-xhdpi")
class OnboardingScreenshotTest {

    @get:Rule
    val compose = createComposeRule()

    @Test
    fun `first run`() {
        capture("01-first-run") { FirstRunScreen(onGetStarted = {}) }
    }

    /** The permission step as almost everyone meets it: a TV that has the settings screen. */
    @Test
    fun `install permission`() {
        capture("02-install-permission") {
            InstallPermissionContent(
                noScreenAvailable = false,
                onOpenSettings = {},
                onSkip = {},
            )
        }
    }

    /**
     * The same step on a television with no per-app permission screen. This is the state
     * that used to be a dead end — the button did nothing and said nothing — so it is worth
     * being able to see that the instructions now stand on their own.
     */
    @Test
    fun `install permission with no settings screen`() {
        capture("03-install-permission-manual") {
            InstallPermissionContent(
                noScreenAvailable = true,
                onOpenSettings = {},
                onSkip = {},
            )
        }
    }

    @Test
    fun `sign in`() {
        capture("04-sign-in") { SignIn(username = "", password = "") }
    }

    @Test
    fun `sign in with credentials typed`() {
        capture("05-sign-in-filled") { SignIn(username = "matt", password = "hunter2") }
    }

    /** The failure everyone hits at least once: it must read as fixable, not as broken. */
    @Test
    fun `sign in rejected`() {
        capture("06-sign-in-error") {
            SignIn(
                username = "matt",
                password = "wrong",
                error = "Memby couldn't sign in. Check the username and password and try again.",
            )
        }
    }

    @Test
    fun `sign in while connecting`() {
        capture("07-sign-in-connecting") {
            SignIn(username = "matt", password = "hunter2", connecting = true)
        }
    }

    /** The same form reached from Settings, which is the only variant with a Back button. */
    @Test
    fun `adding another viewer`() {
        capture("08-add-viewer") { SignIn(username = "", password = "", onBack = {}) }
    }

    @Composable
    private fun SignIn(
        username: String,
        password: String,
        connecting: Boolean = false,
        error: String? = null,
        onBack: (() -> Unit)? = null,
    ) {
        SignInContent(
            username = username,
            password = password,
            onUsernameChange = {},
            onPasswordChange = {},
            onSubmit = {},
            connecting = connecting,
            error = error,
            onBack = onBack,
        )
    }

    private fun capture(name: String, content: @Composable () -> Unit) {
        compose.setContent(content)
        compose.onRoot().captureRoboImage("build/screenshots/onboarding/$name.png")
    }
}
