package com.ponzischeme89.memby.ui

import android.graphics.BitmapFactory
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onRoot
import com.github.takahirom.roborazzi.captureRoboImage
import com.ponzischeme89.memby.data.EmbyOutage
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

/**
 * Renders the Emby outage bar to PNGs under `build/screenshots/emby-outage-banner/`.
 *
 * ```powershell
 * .\gradlew.bat :app:testDebugUnitTest --tests "*EmbyOutageBannerScreenshotTest"
 * ```
 *
 * Drawn over the same playback still the alert bar uses, because that is the situation the
 * red bar is really for: the film has stalled and this is the only thing on screen that
 * explains why. Seeing the two against the same frame is also how their two reds and their
 * shared rule-and-fade stay a deliberate pair rather than a coincidence.
 *
 * [OutageBanner] is rendered rather than [EmbyOutageBanner]: the wrapper's job is the
 * slide-in, and the clock is passed in so the countdown is a chosen value instead of
 * whatever the test machine's uptime happened to be.
 */
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(sdk = [34], qualifiers = "w960dp-h540dp-television-xhdpi")
class EmbyOutageBannerScreenshotTest {

    @get:Rule
    val compose = createComposeRule()

    /** The state the bar spends nearly all of an outage in. */
    @Test
    fun `waiting for the next attempt`() {
        capture("outage-banner-waiting", nextAttemptInMillis = 42_000L)
    }

    /** Freshly armed: the longest number the countdown ever shows. */
    @Test
    fun `full interval remaining`() {
        capture("outage-banner-full-interval", nextAttemptInMillis = 60_000L)
    }

    /** The moment the attempt is due, which is a different string entirely. */
    @Test
    fun `retrying now`() {
        capture("outage-banner-retrying", nextAttemptInMillis = 0L)
    }

    /** Single digits, where the label is at its narrowest and the layout can shift. */
    @Test
    fun `last seconds`() {
        capture("outage-banner-last-seconds", nextAttemptInMillis = 1_000L)
    }

    private fun capture(name: String, nextAttemptInMillis: Long) {
        compose.setContent {
            OutageBannerOnPlaybackStill(
                EmbyOutage(
                    nextAttemptAtMillis = nextAttemptInMillis,
                    retryIntervalSeconds = 60,
                ),
            )
        }
        compose.onRoot().captureRoboImage("build/screenshots/emby-outage-banner/$name.png")
    }

    @Composable
    private fun OutageBannerOnPlaybackStill(outage: EmbyOutage) {
        val playbackStill = requireNotNull(
            javaClass.getResourceAsStream("/playback_alert_preview_still.png"),
        ).use(BitmapFactory::decodeStream).asImageBitmap()
        Box(Modifier.fillMaxSize(), contentAlignment = Alignment.TopCenter) {
            Image(
                bitmap = playbackStill,
                contentDescription = null,
                contentScale = ContentScale.Crop,
                modifier = Modifier.fillMaxSize(),
            )
            // A fixed clock, so each capture shows the countdown value it is named for.
            OutageBanner(outage, nowMillis = { 0L })
        }
    }
}
