package com.fabledsword.minstrel.models

import org.junit.jupiter.api.Test
import kotlin.test.assertEquals

/**
 * The card's subtitle line (#2377). Wording is kept in lockstep with the web
 * client's reasonText() in SuggestionFeed.svelte — these assertions are the
 * record of what that wording IS, so a change on one client without the other
 * shows up as a failure rather than as silent divergence between the two
 * surfaces.
 */
class ArtistSuggestionReasonTest {

    private val seeds = listOf(
        SeedContributionRef(name = "Seed", isLiked = true),
    )

    private fun suggestion(
        matched: List<String> = emptyList(),
        attribution: List<SeedContributionRef> = seeds,
    ) = ArtistSuggestionRef(
        mbid = "mb",
        name = "Candidate",
        attribution = attribution,
        matchedTags = matched,
    )

    @Test
    fun `one matched tag reads in the singular`() {
        assertEquals(
            "Matches your taste in shoegaze.",
            suggestion(matched = listOf("shoegaze")).reasonText,
        )
    }

    @Test
    fun `two matched tags join with and`() {
        assertEquals(
            "Matches your taste in shoegaze and dream pop.",
            suggestion(matched = listOf("shoegaze", "dream pop")).reasonText,
        )
    }

    @Test
    fun `three matched tags use an Oxford comma`() {
        assertEquals(
            "Matches your taste in a, b, and c.",
            suggestion(matched = listOf("a", "b", "c")).reasonText,
        )
    }

    // The server caps at 3, but the client must not render a run-on line if a
    // future server sends more.
    @Test
    fun `more than three matched tags are capped at three`() {
        assertEquals(
            "Matches your taste in a, b, and c.",
            suggestion(matched = listOf("a", "b", "c", "d", "e")).reasonText,
        )
    }

    // The COMMON case: most candidates have no cached tags (#2376), so the card
    // must fall back to seed attribution rather than going blank.
    @Test
    fun `no matched tags falls back to seed attribution`() {
        assertEquals("Because you liked Seed.", suggestion().reasonText)
    }

    // Nothing to say at all — a candidate with neither tags nor attribution
    // yields an empty line, which the tile suppresses rather than rendering as
    // a blank row.
    @Test
    fun `neither tags nor attribution yields an empty line`() {
        assertEquals("", suggestion(attribution = emptyList()).reasonText)
    }

    // The taste reason WINS over attribution when both exist: describing the
    // music beats describing the similarity graph.
    @Test
    fun `a taste match supersedes seed attribution`() {
        val got = suggestion(matched = listOf("shoegaze")).reasonText
        assertEquals("Matches your taste in shoegaze.", got)
    }
}
