package xyz.cottongin.radio247.service

import android.os.Looper
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import androidx.media3.common.Player
import androidx.media3.common.SimpleBasePlayer
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import xyz.cottongin.radio247.audio.IcyMetadata
import xyz.cottongin.radio247.data.model.Station

class RadioPlayerAdapter(
    private val onPlay: () -> Unit,
    private val onStop: () -> Unit,
) : SimpleBasePlayer(Looper.getMainLooper()) {

    @Volatile
    private var _playbackState: Int = Player.STATE_IDLE

    @Volatile
    private var _playWhenReady: Boolean = false

    @Volatile
    private var _mediaMetadata: MediaMetadata = MediaMetadata.EMPTY

    @Volatile
    private var _currentMediaItem: MediaItem? = null

    private val commands = Player.Commands.Builder()
        .add(Player.COMMAND_PLAY_PAUSE)
        .add(Player.COMMAND_STOP)
        .add(Player.COMMAND_GET_CURRENT_MEDIA_ITEM)
        .add(Player.COMMAND_GET_MEDIA_ITEMS_METADATA)
        .build()

    override fun getState(): SimpleBasePlayer.State {
        val mediaItem = _currentMediaItem
        val playlist = if (mediaItem != null) {
            listOf(getPlaceholderMediaItemData(mediaItem))
        } else {
            emptyList()
        }
        return SimpleBasePlayer.State.Builder()
            .setAvailableCommands(commands)
            .setPlaybackState(_playbackState)
            .setPlayWhenReady(_playWhenReady, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
            .setCurrentMediaItemIndex(if (mediaItem != null) 0 else 0)
            .setContentPositionMs(0L)
            .setIsLoading(false)
            .setPlaylist(playlist)
            .build()
    }

    override fun handleSetPlayWhenReady(playWhenReady: Boolean): ListenableFuture<*> {
        _playWhenReady = playWhenReady
        if (playWhenReady) {
            onPlay()
        } else {
            onStop()
        }
        return Futures.immediateVoidFuture()
    }

    override fun handleStop(): ListenableFuture<*> {
        _playWhenReady = false
        onStop()
        return Futures.immediateVoidFuture()
    }

    fun updatePlaybackState(state: PlaybackState) {
        val (newPlayerState, newPlayWhenReady) = when (state) {
            is PlaybackState.Idle -> Player.STATE_IDLE to false
            is PlaybackState.Connecting -> Player.STATE_BUFFERING to true
            is PlaybackState.Playing -> Player.STATE_READY to true
            is PlaybackState.Paused -> Player.STATE_READY to false
            is PlaybackState.Reconnecting -> Player.STATE_BUFFERING to true
        }
        _playbackState = newPlayerState
        _playWhenReady = newPlayWhenReady
        invalidateState()
    }

    fun updateStation(station: Station) {
        _currentMediaItem = MediaItem.Builder()
            .setMediaId("station:${station.id}")
            .setMediaMetadata(
                MediaMetadata.Builder()
                    .setTitle(station.name)
                    .setIsPlayable(true)
                    .build()
            )
            .build()
        invalidateState()
    }

    fun updateMetadata(
        station: Station,
        metadata: IcyMetadata?,
        artworkUri: android.net.Uri? = null
    ) {
        _mediaMetadata = MediaMetadata.Builder()
            .setStation(station.name)
            .setTitle(metadata?.title ?: station.name)
            .setArtist(metadata?.artist)
            .setArtworkUri(artworkUri)
            .setIsPlayable(true)
            .build()
        _currentMediaItem = MediaItem.Builder()
            .setMediaId(_currentMediaItem?.mediaId ?: "station:${station.id}")
            .setMediaMetadata(_mediaMetadata)
            .build()
        invalidateState()
    }

    fun clearState() {
        _currentMediaItem = null
        _mediaMetadata = MediaMetadata.EMPTY
        _playbackState = Player.STATE_IDLE
        _playWhenReady = false
    }
}
