package com.fabledsword.minstrel.models

import kotlinx.datetime.Instant
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals

/**
 * `returnsIn` phrasing for the parked-suggestions list (#2375). The clock is
 * injected rather than frozen, so these assertions are stable.
 */
class SuggestionSnoozeRefTest {

    private val now = 1_800_000_000_000L // fixed epoch ms; any value works

    private fun snoozeIn(days: Double) = SuggestionSnoozeRef(
        mbid = "mb",
        name = "Parked",
        snoozedUntil = Instant
            .fromEpochMilliseconds(now + (days * 86_400_000L).toLong())
            .toString(),
    )

    @Test
    fun `the default 90-day snooze reads as about 3 months`() {
        assertEquals("in about 3 months", snoozeIn(90.0).returnsIn(now))
    }

    @Test
    fun `a month reads in the singular`() {
        assertEquals("in about a month", snoozeIn(30.0).returnsIn(now))
    }

    @Test
    fun `under the month threshold it counts days`() {
        assertEquals("in 14 days", snoozeIn(14.0).returnsIn(now))
    }

    // Pins the days→months boundary. The singular branch was originally dead
    // code because the threshold (45) sat above the divisor (30), so no day
    // count could ever round to one month without being caught by the days
    // branch first. Asserting both sides of the seam keeps that from
    // regressing silently.
    @Test
    fun `the days-to-months boundary is exactly at 30 days`() {
        assertEquals("in 29 days", snoozeIn(29.0).returnsIn(now))
        assertEquals("in about a month", snoozeIn(30.0).returnsIn(now))
    }

    @Test
    fun `well past a month still reads in the singular rather than jumping to two`() {
        assertEquals("in about a month", snoozeIn(40.0).returnsIn(now))
    }

    @Test
    fun `tomorrow is named, not rendered as 1 days`() {
        assertEquals("tomorrow", snoozeIn(1.0).returnsIn(now))
    }

    @Test
    fun `later today rounds down to today rather than going negative`() {
        assertEquals("today", snoozeIn(0.1).returnsIn(now))
    }

    // The server only ever returns unexpired rows, so a past timestamp means
    // our clock and the server's disagree. The row is on screen either way, so
    // say something plausible rather than leaving the line blank.
    @Test
    fun `an already-past expiry degrades to shortly`() {
        assertEquals("shortly", snoozeIn(-5.0).returnsIn(now))
    }

    @Test
    fun `an unparseable timestamp degrades to shortly`() {
        val row = SuggestionSnoozeRef(mbid = "mb", name = "Parked", snoozedUntil = "not-a-date")
        assertEquals("shortly", row.returnsIn(now))
    }

    @Test
    fun `an empty timestamp degrades to shortly`() {
        val row = SuggestionSnoozeRef(mbid = "mb", name = "Parked", snoozedUntil = "")
        assertEquals("shortly", row.returnsIn(now))
    }
}
