package com.ponzischeme89.memby.ui.player

import android.app.Activity
import android.graphics.BitmapFactory
import android.view.LayoutInflater
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import com.github.takahirom.roborazzi.captureRoboImage
import com.ponzischeme89.memby.R
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.annotation.GraphicsMode

/**
 * Renders the cast panel to PNGs under `build/screenshots/cast-panel/`.
 *
 * ```powershell
 * .\gradlew.bat :app:testDebugUnitTest --tests "*CastPanelScreenshotTest"
 * ```
 *
 * Captured over a playback still, because the panel has no card of its own — it is a fade
 * into the picture, and the only way to judge whether the names are legible over a bright
 * frame is to put them over one. Artwork cannot be fetched here, which is the point of the
 * injectable loader: every capture shows the initials fallback, the state a real cast row
 * is partly in anyway.
 */
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(sdk = [34], qualifiers = "w960dp-h540dp-television-xhdpi")
class CastPanelScreenshotTest {

    @Test
    fun `a full cast with the first face focused`() {
        capture(
            name = "cast-panel-loaded",
            state = CastPanelState(
                title = "The Lives of Others",
                loaded = true,
                members = listOf(
                    CastMember(
                        "Ulrich Mühe",
                        "Hauptmann Gerd Wiesler",
                        deathDate = "2007-07-22T00:00:00.0000000Z",
                    ),
                    CastMember("Martina Gedeck", "Christa-Maria Sieland"),
                    CastMember("Sebastian Koch", "Georg Dreyman"),
                    CastMember("Ulrich Tukur", "Oberstleutnant Anton Grubitz"),
                    CastMember("Thomas Thieme", "Minister Bruno Hempf"),
                    CastMember("Hans-Uwe Bauer", "Paul Hauser"),
                    CastMember("Volkmar Kleinert", "Albert Jerska"),
                ),
            ),
            focused = 0,
        )
    }

    /** Focus part-way along, which is what the row looks like while somebody scrolls it. */
    @Test
    fun `focus part way along the row`() {
        capture(
            name = "cast-panel-focus-mid-row",
            state = CastPanelState(
                title = "Arrival",
                loaded = true,
                members = listOf(
                    CastMember("Amy Adams", "Louise Banks"),
                    CastMember("Jeremy Renner", "Ian Donnelly"),
                    CastMember("Forest Whitaker", "Colonel Weber"),
                    CastMember("Michael Stuhlbarg", "Agent Halpern"),
                    CastMember("Tzi Ma", "General Shang"),
                ),
            ),
            focused = 2,
        )
    }

    /** A name with no character recorded — the card must not leave a gap where the role was. */
    @Test
    fun `people with no role`() {
        capture(
            name = "cast-panel-no-roles",
            state = CastPanelState(
                title = "Koyaanisqatsi",
                loaded = true,
                members = listOf(
                    CastMember("Lou Dobbs"),
                    CastMember("Ted Koppel"),
                    CastMember("Philip Glass"),
                ),
            ),
            focused = 0,
        )
    }

    @Test
    fun `selected actor shows biography and filmography`() {
        capture(
            name = "cast-panel-person-profile",
            state = CastPanelState(
                title = "The Lives of Others",
                loaded = true,
                members = listOf(CastMember("Ulrich Mühe", id = "person-1")),
                selectedPerson = CastPersonPanel(
                    id = "person-1",
                    name = "Ulrich Mühe",
                    role = "Hauptmann Gerd Wiesler",
                    birthDate = "1953-06-20T00:00:00.0000000Z",
                    deathDate = "2007-07-22T00:00:00.0000000Z",
                    overview = "A celebrated German actor known for quiet, exacting performances on stage and screen. His portrayal of Gerd Wiesler earned international acclaim.",
                    filmography = listOf(
                        FilmographyCredit("The Lives of Others", 2006),
                        FilmographyCredit("Funny Games", 1997),
                        FilmographyCredit("The Castle", 1997),
                        FilmographyCredit("Benny's Video", 1992),
                    ),
                    loaded = true,
                ),
            ),
        )
    }

    /** Still fetching. The panel opens instantly and says so rather than showing nothing. */
    @Test
    fun `still loading`() {
        capture(name = "cast-panel-loading", state = CastPanelState(title = "Arrival"))
    }

    /** A title Emby holds no cast for, which must read differently from "still loading". */
    @Test
    fun `no cast recorded`() {
        capture(
            name = "cast-panel-empty",
            state = CastPanelState(title = "Home video, 1998", loaded = true),
        )
    }

    @Test
    fun `initials cover a mononym, a middle name and a blank`() {
        assertEquals("AA", castInitials("Amy Adams"))
        // First and surname, not the first two words: the surname is what identifies
        // somebody, so a middle name is skipped rather than taking the second slot.
        assertEquals("PH", castInitials("Philip Seymour Hoffman"))
        assertEquals("C", castInitials("Cher"))
        assertEquals("AA", castInitials("  amy   adams  "))
        assertEquals("", castInitials("   "))
        assertEquals(
            "20 June 1953 – 22 July 2007",
            personLifeDates("1953-06-20T00:00:00Z", "2007-07-22T00:00:00Z"),
        )
    }

    private fun capture(name: String, state: CastPanelState, focused: Int? = null) {
        val activity = Robolectric.buildActivity(Activity::class.java).setup().get()
        val root = FrameLayout(activity)
        root.addView(
            ImageView(activity).apply {
                scaleType = ImageView.ScaleType.CENTER_CROP
                setImageBitmap(previewArtwork())
            },
            FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT,
                FrameLayout.LayoutParams.MATCH_PARENT,
            ),
        )

        val overlay = LayoutInflater.from(activity)
            .inflate(R.layout.player_cast_overlay, root, false)
        root.addView(overlay)
        overlay.visibility = View.VISIBLE
        bindCastPanel(overlay, state)
        activity.setContentView(root)

        if (focused != null) {
            // Robolectric starts in touch mode, where a focusable card refuses focus and the
            // capture would show every face unfocused. This leaves touch mode the way a
            // D-pad press does.
            val card = requireNotNull(
                overlay.findViewById<LinearLayout>(R.id.player_cast_people).getChildAt(focused),
            )
            card.requestFocusFromTouch()
            check(card.isFocused) { "the card to capture under focus never took it" }
        }

        root.captureRoboImage("build/screenshots/cast-panel/$name.png")
    }

    private fun previewArtwork() =
        javaClass.classLoader
            ?.getResourceAsStream("home_hero_preview_art.png")
            ?.use(BitmapFactory::decodeStream)
}
