package ca.ksamad.encore.mpd.model

import ca.ksamad.encore.mpd.MpdResponse
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test

class MpdModelTest {
    @Test
    fun status_parsesTypicalPlayingSnapshot() {
        val s =
            MpdStatus.from(
                mapOf(
                    "volume" to "80",
                    "repeat" to "0",
                    "random" to "1",
                    "single" to "oneshot",
                    "consume" to "0",
                    "playlist" to "17",
                    "playlistlength" to "12",
                    "state" to "play",
                    "song" to "3",
                    "songid" to "104",
                    "elapsed" to "42.5",
                    "duration" to "215.3",
                    "bitrate" to "320",
                    "audio" to "44100:16:2",
                )
            )
        assertEquals(80, s.volume)
        assertFalse(s.repeat)
        assertTrue(s.random)
        assertTrue(s.single) // "oneshot" counts as single
        assertEquals(PlayerState.PLAY, s.state)
        assertEquals(3, s.song)
        assertEquals(42.5, s.elapsed!!, 0.0001)
        assertEquals(215.3, s.duration!!, 0.0001)
        assertFalse(s.updating) // no updating_db field → not scanning
    }

    @Test
    fun status_missingMixerYieldsNullVolume() {
        val s = MpdStatus.from(mapOf("volume" to "-1", "state" to "stop"))
        assertNull(s.volume)
        assertEquals(PlayerState.STOP, s.state)
        assertEquals(0, s.playlistLength)
    }

    @Test
    fun status_updatingDbFlagsScanInProgress() {
        val s = MpdStatus.from(mapOf("state" to "stop", "updating_db" to "3"))
        assertTrue(s.updating)
    }

    @Test
    fun song_parsesTagsAndDuration() {
        val song =
            MpdSong.from(
                mapOf(
                    "file" to "music/nin/closer.flac",
                    "Title" to "Closer",
                    "Artist" to "Nine Inch Nails",
                    "Album" to "The Downward Spiral",
                    "Track" to "6",
                    "duration" to "374.146",
                    "Pos" to "5",
                    "Id" to "42",
                )
            )!!
        assertEquals("music/nin/closer.flac", song.uri)
        assertEquals("Closer", song.title)
        assertEquals("Nine Inch Nails", song.artist)
        assertEquals(374.146, song.duration!!, 0.0001)
        assertEquals(42, song.id)
    }

    @Test
    fun song_returnsNullWithoutFileKey() {
        assertNull(MpdSong.from(mapOf("directory" to "music/nin")))
    }

    @Test
    fun song_fallsBackToLegacyTimeField() {
        val song = MpdSong.from(mapOf("file" to "a.mp3", "Time" to "180"))!!
        assertEquals(180.0, song.duration!!, 0.0001)
    }

    @Test
    fun response_splitSeparatesRepeatedSongBlocks() {
        // Two songs from a playlistinfo-style response, split on "file".
        val resp =
            MpdResponse(
                listOf(
                    "file" to "a.mp3",
                    "Title" to "A",
                    "Pos" to "0",
                    "Id" to "1",
                    "file" to "b.mp3",
                    "Title" to "B",
                    "Pos" to "1",
                    "Id" to "2",
                )
            )
        val songs = resp.split().mapNotNull { MpdSong.from(it) }
        assertEquals(2, songs.size)
        assertEquals("A", songs[0].title)
        assertEquals("b.mp3", songs[1].uri)
        assertEquals(2, songs[1].id)
    }

    @Test
    fun albums_parseGroupedByArtist() {
        // `list album group albumartist` style output.
        val resp =
            MpdResponse(
                listOf(
                    "AlbumArtist" to "Pink Floyd",
                    "Album" to "Animals",
                    "Album" to "The Wall",
                    "AlbumArtist" to "Daft Punk",
                    "Album" to "Discovery",
                )
            )
        val albums = MpdAlbum.listFrom(resp)
        assertEquals(3, albums.size)
        assertEquals(MpdAlbum("Animals", "Pink Floyd"), albums[0])
        assertEquals(MpdAlbum("The Wall", "Pink Floyd"), albums[1])
        assertEquals(MpdAlbum("Discovery", "Daft Punk"), albums[2])
    }

    @Test
    fun albums_albumWithoutArtistGroupHasNullArtist() {
        val resp = MpdResponse(listOf("Album" to "Untitled"))
        assertEquals(listOf(MpdAlbum("Untitled", null)), MpdAlbum.listFrom(resp))
    }

    @Test
    fun statistics_parseCounts() {
        val stats =
            MpdStatistics.from(
                mapOf(
                    "artists" to "312",
                    "albums" to "540",
                    "songs" to "8123",
                    "uptime" to "98765",
                    "db_update" to "1700000000",
                )
            )
        assertEquals(312, stats.artists)
        assertEquals(8123, stats.songs)
        assertEquals(1700000000L, stats.dbUpdateEpochSeconds)
    }
}
