package com.fabledsword.minstrel.player

import android.os.Bundle
import androidx.media3.session.MediaSession
import androidx.media3.session.SessionCommand
import androidx.media3.session.SessionResult
import com.fabledsword.minstrel.likes.data.LikesRepository
import com.fabledsword.minstrel.likes.data.LikesRepository.Companion.ENTITY_TRACK
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch

/**
 * MediaSession callback that adds the like/heart custom command to
 * every connecting controller (notification, lock screen, Pixel Watch,
 * Android Auto) and routes taps through [LikesRepository.toggleLike]
 * so they inherit the offline-resilient MutationQueue path.
 *
 * The [onConnect] grant is REQUIRED — without it the button is
 * silently invisible on some surfaces (Media3 issue #2679). See the
 * spec at docs/superpowers/specs/2026-06-02-android-media3-like-button-design.md.
 *
 * Suspend work in [onCustomCommand] is launched on [scope] (a
 * service-lifetime scope) so the callback returns synchronously and
 * the controller does not block on Room + REST. State updates flow
 * back through [LikesRepository.observeIsLiked] so the icon refreshes
 * via the like-state job in [MinstrelPlayerService].
 */
class LikeMediaCallback(
    private val likes: LikesRepository,
    private val scope: CoroutineScope,
) : MediaSession.Callback {

    override fun onConnect(
        session: MediaSession,
        controller: MediaSession.ControllerInfo,
    ): MediaSession.ConnectionResult {
        val grants = MediaSession.ConnectionResult.DEFAULT_SESSION_COMMANDS
            .buildUpon()
            .add(SessionCommand(CMD_TOGGLE_LIKE, Bundle.EMPTY))
            .build()
        return MediaSession.ConnectionResult.AcceptedResultBuilder(session)
            .setAvailableSessionCommands(grants)
            .build()
    }

    override fun onCustomCommand(
        session: MediaSession,
        controller: MediaSession.ControllerInfo,
        customCommand: SessionCommand,
        args: Bundle,
    ): ListenableFuture<SessionResult> {
        val code = if (customCommand.customAction == CMD_TOGGLE_LIKE) {
            launchToggleForCurrent(session)
        } else {
            SessionResult.RESULT_ERROR_NOT_SUPPORTED
        }
        return Futures.immediateFuture(SessionResult(code))
    }

    private fun launchToggleForCurrent(session: MediaSession): Int {
        val mediaId = session.player.currentMediaItem?.mediaId
            ?: return SessionResult.RESULT_INFO_SKIPPED
        scope.launch {
            val current = likes.observeIsLiked(ENTITY_TRACK, mediaId).first()
            likes.toggleLike(ENTITY_TRACK, mediaId, !current)
        }
        return SessionResult.RESULT_SUCCESS
    }

    companion object {
        /** Custom-action key for the like/heart button. Namespaced so
         *  future custom commands (output picker, etc.) don't collide. */
        const val CMD_TOGGLE_LIKE: String = "minstrel.toggle_like"
    }
}
