package ca.ksamad.encore.mpd.model

/** Player transport state as reported by the `state` field of `status`. */
enum class PlayerState {
    PLAY,
    PAUSE,
    STOP,
    UNKNOWN;

    companion object {
        fun parse(raw: String?): PlayerState =
            when (raw) {
                "play" -> PLAY
                "pause" -> PAUSE
                "stop" -> STOP
                else -> UNKNOWN
            }
    }
}

/**
 * A snapshot of the player, parsed from a `status` response. Fields absent from the response (e.g.
 * `song`/`elapsed` while stopped) are `null`.
 *
 * See the MPD protocol docs for field semantics. Only the fields a remote UI actually drives are
 * surfaced here; more can be added as needed.
 */
data class MpdStatus(
    val volume: Int?, // 0..100; null when MPD reports -1 (output closed / volume unavailable)
    val repeat: Boolean,
    val random: Boolean,
    val single: Boolean, // true for "1" or "oneshot"
    val consume: Boolean,
    val playlistVersion: Int?, // queue version; bumps on every queue change
    val playlistLength: Int, // number of songs in the queue
    val state: PlayerState,
    val song: Int?, // queue position of the current song
    val songId: Int?, // stable id of the current song
    val nextSong: Int?,
    val nextSongId: Int?,
    val elapsed: Double?, // seconds into the current song (fractional)
    val duration: Double?, // length of the current song in seconds
    val bitrate: Int?, // instantaneous kbps
    val audio: String?, // e.g. "44100:16:2"
    val error: String?, // last player error, if any
    val updating: Boolean = false, // true while the server is scanning its database (`updating_db`)
) {
    companion object {
        fun from(values: Map<String, String>): MpdStatus =
            MpdStatus(
                volume = values["volume"]?.toIntOrNull()?.takeIf { it >= 0 },
                repeat = values["repeat"] == "1",
                random = values["random"] == "1",
                single = values["single"].let { it == "1" || it == "oneshot" },
                consume = values["consume"] == "1",
                playlistVersion = values["playlist"]?.toIntOrNull(),
                playlistLength = values["playlistlength"]?.toIntOrNull() ?: 0,
                state = PlayerState.parse(values["state"]),
                song = values["song"]?.toIntOrNull(),
                songId = values["songid"]?.toIntOrNull(),
                nextSong = values["nextsong"]?.toIntOrNull(),
                nextSongId = values["nextsongid"]?.toIntOrNull(),
                elapsed = values["elapsed"]?.toDoubleOrNull(),
                duration = values["duration"]?.toDoubleOrNull(),
                bitrate = values["bitrate"]?.toIntOrNull(),
                audio = values["audio"],
                error = values["error"],
                // Present (a job id) only while a database update/rescan is running.
                updating = values["updating_db"] != null,
            )
    }
}
