package com.ponzischeme89.memby.data

import com.ponzischeme89.memby.data.model.BaseItem
import com.ponzischeme89.memby.data.model.EmbyPerson
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Test

class CastMetadataTest {

    @Test
    fun `episode without cast falls back to its series cast`() = runTest {
        val seriesCast = listOf(actor("series-lead"))
        val items = mapOf(
            "episode" to BaseItem(id = "episode", type = "Episode", seriesId = "series"),
            "series" to BaseItem(id = "series", type = "Series", people = seriesCast),
        )
        val requested = mutableListOf<String>()

        val result = resolveCast("episode") { id ->
            requested += id
            requireNotNull(items[id])
        }

        assertEquals(seriesCast, result)
        assertEquals(listOf("episode", "series"), requested)
    }

    @Test
    fun `episode cast takes precedence over series cast`() = runTest {
        val guestCast = listOf(actor("guest"))
        val requested = mutableListOf<String>()

        val result = resolveCast("episode") { id ->
            requested += id
            BaseItem(
                id = id,
                type = "Episode",
                seriesId = "series",
                people = guestCast,
            )
        }

        assertEquals(guestCast, result)
        assertEquals(listOf("episode"), requested)
    }

    @Test
    fun `non-episode without cast does not use a series fallback`() = runTest {
        val requested = mutableListOf<String>()

        val result = resolveCast("movie") { id ->
            requested += id
            BaseItem(id = id, type = "Movie", seriesId = "series")
        }

        assertEquals(emptyList<EmbyPerson>(), result)
        assertEquals(listOf("movie"), requested)
    }

    @Test
    fun `cast contains actors and preserves Emby order`() {
        val item = BaseItem(
            id = "movie",
            people = listOf(
                EmbyPerson(id = "director", name = "Director", type = "Director"),
                EmbyPerson(id = "lead", name = "Lead", role = "Detective", type = "Actor"),
                EmbyPerson(id = "support", name = "Support", role = "Doctor", type = "Actor"),
            ),
        )

        assertEquals(listOf("lead", "support"), item.cast.map(EmbyPerson::id))
        assertEquals("Detective", item.cast.first().role)
    }

    @Test
    fun `decodes emby people and portrait tags`() {
        val item = Json { ignoreUnknownKeys = true }.decodeFromString<BaseItem>(
            """
            {
              "Id":"movie",
              "Name":"Example",
              "Type":"Movie",
              "People":[{
                "Id":"person-1",
                "Name":"Alex Actor",
                "Role":"Morgan",
                "Type":"Actor",
                "PrimaryImageTag":"portrait-tag"
              }]
            }
            """.trimIndent(),
        )

        assertEquals("person-1", item.cast.single().id)
        assertEquals("portrait-tag", item.cast.single().primaryImageTag)
    }

    @Test
    fun `decodes person biography and life dates`() {
        val person = Json { ignoreUnknownKeys = true }.decodeFromString<BaseItem>(
            """
            {
              "Id":"person-1",
              "Name":"Alex Actor",
              "Type":"Person",
              "Overview":"A stage and screen performer.",
              "PremiereDate":"1940-01-02T00:00:00.0000000Z",
              "EndDate":"2020-03-04T00:00:00.0000000Z"
            }
            """.trimIndent(),
        )

        assertEquals("A stage and screen performer.", person.overview)
        assertEquals("1940-01-02T00:00:00.0000000Z", person.premiereDate)
        assertEquals("2020-03-04T00:00:00.0000000Z", person.endDate)
    }

    private fun actor(id: String) = EmbyPerson(id = id, name = id, type = "Actor")
}
