package com.ponzischeme89.memby.ui

import com.ponzischeme89.memby.ui.detail.DetailPosition
import com.ponzischeme89.memby.ui.detail.DetailPositionStore
import com.ponzischeme89.memby.ui.detail.DetailTab
import com.ponzischeme89.memby.ui.detail.DetailZone
import com.ponzischeme89.memby.ui.detail.detailTab
import com.ponzischeme89.memby.ui.detail.detailTabs
import org.junit.Assert.assertEquals
import org.junit.Test

/**
 * The two rules the detail pages depend on and cannot check on a device: the tab strip is
 * decided by what the item *is*, and a page's position survives being closed.
 */
class DetailNavigationTest {

    @Test
    fun `a movie always offers the same three tabs`() {
        assertEquals(
            listOf(DetailTab.OVERVIEW, DetailTab.MORE_LIKE_THIS, DetailTab.CAST_DETAILS),
            detailTabs(isSeries = false),
        )
    }

    @Test
    fun `a series always offers episodes`() {
        assertEquals(
            listOf(DetailTab.OVERVIEW, DetailTab.EPISODES, DetailTab.MORE_LIKE_THIS, DetailTab.CAST_DETAILS),
            detailTabs(isSeries = true),
        )
    }

    /**
     * The regression this replaced: the strip used to be built from what had loaded, so a
     * movie opened with one tab and grew two more when its metadata arrived — moving the
     * strip under whatever the viewer was already pressing.
     */
    @Test
    fun `the strip does not depend on loaded metadata`() {
        assertEquals(detailTabs(isSeries = false), detailTabs(isSeries = false))
        assertEquals(detailTabs(isSeries = true), detailTabs(isSeries = true))
    }

    @Test
    fun `an episodes key remembered from a series falls back on a movie`() {
        assertEquals(
            DetailTab.OVERVIEW,
            detailTab(DetailTab.EPISODES.key, detailTabs(isSeries = false)),
        )
        assertEquals(
            DetailTab.EPISODES,
            detailTab(DetailTab.EPISODES.key, detailTabs(isSeries = true)),
        )
    }

    @Test
    fun `an unknown key falls back to overview`() {
        assertEquals(DetailTab.OVERVIEW, detailTab("nonsense", detailTabs(isSeries = true)))
    }

    @Test
    fun `a page reopens where it was left`() {
        val store = DetailPositionStore()
        store.update("show-1") {
            it.copy(tabKey = DetailTab.EPISODES.key, season = 3, zone = DetailZone.CONTENT)
        }
        store.update("show-1") { it.copy(episodeIndex = 6) }

        assertEquals(
            DetailPosition(
                tabKey = DetailTab.EPISODES.key,
                season = 3,
                zone = DetailZone.CONTENT,
                episodeIndex = 6,
            ),
            store.get("show-1"),
        )
    }

    @Test
    fun `an unvisited page opens on overview with focus on play`() {
        val position = DetailPositionStore().get("never-opened")

        assertEquals(DetailTab.OVERVIEW.key, position.tabKey)
        assertEquals(DetailZone.PLAY, position.zone)
        assertEquals(null, position.season)
    }

    @Test
    fun `play focus pins the complete hero while lower zones release scrolling`() {
        assertEquals(0, detailHeroScrollTarget(DetailZone.PLAY))
        assertEquals(null, detailHeroScrollTarget(DetailZone.TABS))
        assertEquals(null, detailHeroScrollTarget(DetailZone.CONTENT))
        assertEquals(null, detailHeroScrollTarget(DetailZone.RELATED))
    }

    @Test
    fun `the store is capped and keeps the most recently used`() {
        val store = DetailPositionStore(maxEntries = 3)
        listOf("a", "b", "c").forEach { id ->
            store.update(id) { it.copy(tabKey = DetailTab.CAST_DETAILS.key) }
        }
        // Touching "a" makes it the newest, so "b" is what falls out.
        store.get("a")
        store.update("d") { it.copy(tabKey = DetailTab.MORE_LIKE_THIS.key) }

        assertEquals(3, store.size())
        assertEquals(DetailTab.CAST_DETAILS.key, store.get("a").tabKey)
        assertEquals(DetailTab.OVERVIEW.key, store.get("b").tabKey)
        assertEquals(DetailTab.MORE_LIKE_THIS.key, store.get("d").tabKey)
    }

    @Test
    fun `a blank item id is never stored`() {
        val store = DetailPositionStore()
        store.update("") { it.copy(tabKey = DetailTab.CAST_DETAILS.key) }

        assertEquals(0, store.size())
    }
}
