package com.swoosh.microblog.ui.feed

import org.junit.Assert.*
import org.junit.Test
import java.time.Instant
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit

class FormatRelativeTimeTest {

    private fun instantMinusMinutes(minutes: Long): String {
        return Instant.now().minus(minutes, ChronoUnit.MINUTES)
            .atZone(ZoneId.of("UTC"))
            .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
    }

    private fun instantMinusHours(hours: Long): String {
        return Instant.now().minus(hours, ChronoUnit.HOURS)
            .atZone(ZoneId.of("UTC"))
            .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
    }

    private fun instantMinusDays(days: Long): String {
        return Instant.now().minus(days, ChronoUnit.DAYS)
            .atZone(ZoneId.of("UTC"))
            .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
    }

    @Test
    fun `null input returns empty string`() {
        assertEquals("", formatRelativeTime(null))
    }

    @Test
    fun `empty string returns empty string`() {
        assertEquals("", formatRelativeTime(""))
    }

    @Test
    fun `invalid date string returns empty string`() {
        assertEquals("", formatRelativeTime("not-a-date"))
    }

    @Test
    fun `just now returns now`() {
        val now = Instant.now().atZone(ZoneId.of("UTC"))
            .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
        assertEquals("now", formatRelativeTime(now))
    }

    @Test
    fun `30 seconds ago returns now`() {
        val thirtySecsAgo = Instant.now().minusSeconds(30)
            .atZone(ZoneId.of("UTC"))
            .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
        assertEquals("now", formatRelativeTime(thirtySecsAgo))
    }

    @Test
    fun `1 minute ago returns 1m ago`() {
        val result = formatRelativeTime(instantMinusMinutes(1))
        assertEquals("1m ago", result)
    }

    @Test
    fun `5 minutes ago returns 5m ago`() {
        val result = formatRelativeTime(instantMinusMinutes(5))
        assertEquals("5m ago", result)
    }

    @Test
    fun `59 minutes ago returns 59m ago`() {
        val result = formatRelativeTime(instantMinusMinutes(59))
        assertEquals("59m ago", result)
    }

    @Test
    fun `1 hour ago returns 1h ago`() {
        val result = formatRelativeTime(instantMinusHours(1))
        assertEquals("1h ago", result)
    }

    @Test
    fun `12 hours ago returns 12h ago`() {
        val result = formatRelativeTime(instantMinusHours(12))
        assertEquals("12h ago", result)
    }

    @Test
    fun `23 hours ago returns 23h ago`() {
        val result = formatRelativeTime(instantMinusHours(23))
        assertEquals("23h ago", result)
    }

    @Test
    fun `1 day ago returns 1d ago`() {
        val result = formatRelativeTime(instantMinusDays(1))
        assertEquals("1d ago", result)
    }

    @Test
    fun `3 days ago returns 3d ago`() {
        val result = formatRelativeTime(instantMinusDays(3))
        assertEquals("3d ago", result)
    }

    @Test
    fun `6 days ago returns 6d ago`() {
        val result = formatRelativeTime(instantMinusDays(6))
        assertEquals("6d ago", result)
    }

    @Test
    fun `7 days ago returns formatted date`() {
        val sevenDaysAgo = Instant.now().minus(7, ChronoUnit.DAYS)
        val expected = DateTimeFormatter.ofPattern("MMM d")
            .format(ZonedDateTime.ofInstant(sevenDaysAgo, ZoneId.systemDefault()))
        val result = formatRelativeTime(instantMinusDays(7))
        assertEquals(expected, result)
    }

    @Test
    fun `30 days ago returns formatted date`() {
        val thirtyDaysAgo = Instant.now().minus(30, ChronoUnit.DAYS)
        val expected = DateTimeFormatter.ofPattern("MMM d")
            .format(ZonedDateTime.ofInstant(thirtyDaysAgo, ZoneId.systemDefault()))
        val result = formatRelativeTime(instantMinusDays(30))
        assertEquals(expected, result)
    }

    @Test
    fun `parses ISO instant format`() {
        val iso = Instant.now().minus(5, ChronoUnit.MINUTES).toString()
        val result = formatRelativeTime(iso)
        assertEquals("5m ago", result)
    }

    @Test
    fun `parses zoned datetime with timezone offset`() {
        val zoned = Instant.now().minus(2, ChronoUnit.HOURS)
            .atZone(ZoneId.of("America/New_York"))
            .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
        val result = formatRelativeTime(zoned)
        assertEquals("2h ago", result)
    }

    @Test
    fun `parses zoned datetime with Z suffix`() {
        val utc = Instant.now().minus(3, ChronoUnit.HOURS)
            .atZone(ZoneId.of("UTC"))
            .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
        val result = formatRelativeTime(utc)
        assertEquals("3h ago", result)
    }
}
