package com.player.musicoo.activity

import android.annotation.SuppressLint
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.view.View
import android.view.animation.AnimationUtils
import androidx.annotation.OptIn
import androidx.media3.common.MediaItem
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.gyf.immersionbar.ktx.immersionBar
import com.player.musicoo.R
import com.player.musicoo.adapter.PlayListAdapter
import com.player.musicoo.databinding.ActivityMoPlayDetailsBinding
import com.player.musicoo.innertube.Innertube
import com.player.musicoo.media.MediaControllerManager
import com.player.musicoo.media.SongRadio
import com.player.musicoo.util.LogTag.LogD
import com.player.musicoo.util.asMediaItem
import com.player.musicoo.util.convertMillisToMinutesAndSecondsString
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.selects.select

@OptIn(UnstableApi::class)
class MoPlayDetailsActivity : MoBaseActivity(), Player.Listener {

    companion object {
        const val PLAY_DETAILS_VIDEO_ID = "play_details_videoId"
        const val PLAY_DETAILS_PLAY_LIST_ID = "play_details_playlistId"
        const val PLAY_DETAILS_PLAY_LIST_SET_VIDEO_ID = "play_details_play_list_set_video_id"
        const val PLAY_DETAILS_PLAY_PARAMS = "play_details_play_params"
        const val PLAY_DETAILS_NAME = "play_details_name"
        const val PLAY_DETAILS_DESC = "play_details_desc"
        const val PLAY_DETAILS_COME_FROM = "PLAY_DETAILS_COME_FROM"
    }

    private lateinit var binding: ActivityMoPlayDetailsBinding

    private var currentVideoID = ""

    private var comeFrom: Class<*>? = null
    private var playListAdapter: PlayListAdapter? = null

    private fun initImmersionBar() {
        immersionBar {
            statusBarDarkFont(false)
            statusBarView(binding.view)
        }
    }

    override suspend fun main() {
        binding = ActivityMoPlayDetailsBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initImmersionBar()
        initClick()
        initPlayerListener()

        val videoId = intent.getStringExtra(PLAY_DETAILS_VIDEO_ID)
        val playlistId = intent.getStringExtra(PLAY_DETAILS_PLAY_LIST_ID)
        val playlistSetVideoId = intent.getStringExtra(PLAY_DETAILS_PLAY_LIST_SET_VIDEO_ID)
        val params = intent.getStringExtra(PLAY_DETAILS_PLAY_PARAMS)

        comeFrom = intent.getSerializableExtra(PLAY_DETAILS_COME_FROM) as Class<*>?
        if (comeFrom != null && comeFrom == PrimaryActivity::class.java) {
            // 处理来自 PrimaryActivity 的情况
            updateCurrentMediaItemInfo()
        } else {
            if (meController != null && meController.currentMediaItem != null && videoId == meController.currentMediaItem?.mediaId) {
                //进入的id与当前的id一样就不重新去获取播放
                updateCurrentMediaItemInfo()
            } else {
                binding.nameTv.text = intent.getStringExtra(PLAY_DETAILS_NAME)
                binding.descTv.text = intent.getStringExtra(PLAY_DETAILS_DESC)

                if (videoId.isNullOrEmpty()) {
                    finish()
                    return
                }
                //传入进来的ID，就是进入此界面的当前ID
                currentVideoID = videoId
                //根据进来界面的当前ID来获取资源。
                initData(
                    videoId,
                    playlistId,
                    playlistSetVideoId,
                    params
                )
            }

        }

        onReceive()
    }

    private suspend fun onReceive() {
        while (isActive) {
            select<Unit> {
                events.onReceive {
                    when (it) {
                        Event.ActivityOnResume -> {
                            activityOnResume()
                        }

                        else -> {}
                    }
                }
            }
        }
    }

    private fun activityOnResume() {
        if (comeFrom != null && comeFrom == PrimaryActivity::class.java) {
            if (meController != null && meController.currentMediaItem != null) {
                updateInfoUi(meController.currentMediaItem)
            }
        }
    }

    private fun initPlayerListener() {
        meController?.addListener(playerListener)
    }

    private fun updateCurrentMediaItemInfo() {
        if (meController != null && meController.currentMediaItem != null) {
            binding.playbackErrorLayout.visibility = View.GONE
            binding.loadingView.visibility = View.GONE
            binding.disableClicksLayout.visibility = View.GONE
            val currentString =
                convertMillisToMinutesAndSecondsString(MediaControllerManager.getCurrentPosition())
            binding.progressDurationTv.text = currentString
            if (MediaControllerManager.getDuration() > 0) {
                binding.totalDurationTv.visibility = View.VISIBLE
            } else {
                binding.totalDurationTv.visibility = View.GONE
            }

            binding.totalDurationTv.text =
                convertMillisToMinutesAndSecondsString(MediaControllerManager.getDuration())
            binding.sbProgress.valueTo = MediaControllerManager.getDuration().toFloat()
            binding.sbProgress.value = MediaControllerManager.getCurrentPosition().toFloat()
            updateProgressState()

            binding.progressBar.progress = MediaControllerManager.getBufferedPosition().toInt()
            binding.progressBar.max = MediaControllerManager.getDuration().toInt()
            updateProgressBufferingState()

            val mediaItemCount = meController.mediaItemCount
            val allMediaItems: MutableList<MediaItem> = mutableListOf()
            for (index in 0 until mediaItemCount) {
                val mediaItemAt = meController.getMediaItemAt(index)
                allMediaItems.add(mediaItemAt)
            }
            playListAdapter = PlayListAdapter(
                this@MoPlayDetailsActivity,
                allMediaItems
            )
            binding.playListRv.layoutManager =
                LinearLayoutManager(
                    this@MoPlayDetailsActivity,
                    LinearLayoutManager.VERTICAL,
                    false
                )
            binding.playListRv.adapter = playListAdapter
        }
    }

    private fun initClick() {
        binding.backBtn.setOnClickListener {
            finish()
        }
        binding.tryAgainBtn.setOnClickListener {
            if (meController != null) {
                updateInfoUi(meController.currentMediaItem)
                updateProgressState()
                if (!meController.isPlaying) {
                    meController.prepare()
                    meController.play()
                }
            }
        }
        binding.playLayoutBtn.setOnClickListener {
            if (meController != null) {
                if (meController.isPlaying) {
                    meController.pause()
                    updatePlayState(false)
                } else {
                    meController.play()
                    updatePlayState(true)
                }
                updateProgressState()
            }
        }
        binding.playSkipBackBtn.setOnClickListener {
            if (meController != null) {
                meController.seekToPreviousMediaItem()
                updateProgressUi()
                updateInfoUi(meController.currentMediaItem)
                updateProgressState()
                if (!meController.isPlaying) {
                    meController.prepare()
                    meController.play()
                }
            }
        }
        binding.playSkipForwardBtn.setOnClickListener {
            if (meController != null) {
                meController.seekToNextMediaItem()
                updateProgressUi()
                updateInfoUi(meController.currentMediaItem)
                updateProgressState()
                if (!meController.isPlaying) {
                    meController.prepare()
                    meController.play()
                }
            }
        }
        binding.listLayoutBtn.setOnClickListener {
            toggleBottomLayout()
        }
        binding.bottomCloseBtn.setOnClickListener {
            toggleBottomLayout()
        }
        binding.bottomBlankLayout.setOnClickListener {
            toggleBottomLayout()
        }
        binding.progressBar.progress = 0
        binding.sbProgress.value = 0f
        binding.sbProgress.addOnChangeListener { slider, value, fromUser ->
            if (fromUser) {
                if (meController != null) {
                    meController.seekTo(value.toLong())
                    val ss = meController.isPlaying
                    if (!ss) {
                        meController.play()
                    }
                }
            }
        }
    }

    private fun initData(
        videoId: String,
        playlistId: String? = null,
        playlistSetVideoId: String? = null,
        parameters: String? = null
    ) {
        SongRadio(
            videoId,
            playlistId,
            playlistSetVideoId,
            parameters
        ).let {
            launch(Dispatchers.Main) {
                val songRadioList = it.process()//获取到的资源集合

                if (songRadioList.isEmpty()) {//集合为空则展示错误提示
                    binding.loadingView.visibility = View.GONE
                    binding.disableClicksLayout.visibility = View.GONE
                    binding.playbackErrorLayout.visibility = View.VISIBLE
                } else {
                    playListAdapter = PlayListAdapter(
                        this@MoPlayDetailsActivity,
                        songRadioList.map(Innertube.SongItem::asMediaItem)
                    )
                    binding.playListRv.layoutManager =
                        LinearLayoutManager(
                            this@MoPlayDetailsActivity,
                            LinearLayoutManager.VERTICAL,
                            false
                        )
                    binding.playListRv.adapter = playListAdapter
                }

                if (isFinishing) {
                    return@launch
                }

                var mediaItem: MediaItem? = null
                for (song: Innertube.SongItem in songRadioList) {
                    if (song.key == currentVideoID) {//判断当前ID得到一个mediaItem
                        mediaItem = song.asMediaItem
                        break
                    }
                }

                if (mediaItem != null) {
                    updateInfoUi(mediaItem)

                    binding.playbackErrorLayout.visibility = View.GONE

                    binding.totalDurationTv.visibility = View.GONE


                    val newMediaItem =
                        MediaItem.Builder()
                            .setMediaId(videoId)
                            .setUri(videoId)
                            .setCustomCacheKey(videoId)
                            .setMediaMetadata(
                                mediaItem.mediaMetadata
                            )
                            .build()

                    meController?.let {
                        it.setMediaItem(newMediaItem, true)
                        it.prepare()
                        it.play()

                        //过滤掉进入页面的id得到集合addMediaItems
                        val mediaItems = songRadioList.map(Innertube.SongItem::asMediaItem)
                            .filter { filter -> filter.mediaId != videoId }
                        it.addMediaItems(mediaItems)
                    }
                } else {
                    binding.playbackErrorLayout.visibility = View.VISIBLE
                }
            }
        }
    }

    private val playerListener = object : Player.Listener {
        @SuppressLint("NotifyDataSetChanged")
        override fun onPositionDiscontinuity(
            oldPosition: Player.PositionInfo,
            newPosition: Player.PositionInfo,
            reason: Int
        ) {
            //保证自动播放完毕当前歌曲与通知切换歌曲可以更新UI信息
            if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION
                || reason == Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT
            ) {
                updateProgressUi()
                updateInfoUi(meController?.currentMediaItem)
                if (playListAdapter != null) {
                    playListAdapter?.notifyDataSetChanged()
                }
            }
        }

        override fun onPlayerError(error: PlaybackException) {
            LogD(TAG, "onPlayerError error= $error")
            binding.playbackErrorLayout.visibility = View.VISIBLE//展示错误提示

            updatePlayState(false)
        }

        override fun onPlayWhenReadyChanged(
            playWhenReady: Boolean,
            reason: Int
        ) {
            updatePlayState(playWhenReady)
            updateProgressState()
        }

        override fun onPlaybackStateChanged(playbackState: Int) {
            when (playbackState) {
                Player.STATE_BUFFERING -> {
                    binding.loadingView.visibility = View.VISIBLE
                    binding.disableClicksLayout.visibility = View.VISIBLE
                    binding.playbackErrorLayout.visibility = View.GONE
                }

                Player.STATE_READY -> {
                    binding.playbackErrorLayout.visibility = View.GONE
                    binding.loadingView.visibility = View.GONE
                    binding.disableClicksLayout.visibility = View.GONE
                    binding.totalDurationTv.visibility = View.VISIBLE
                    binding.totalDurationTv.text =
                        convertMillisToMinutesAndSecondsString(
                            MediaControllerManager.getDuration()
                        )
                    binding.sbProgress.valueTo =
                        MediaControllerManager.getDuration().toFloat()
                    binding.progressBar.max =
                        MediaControllerManager.getDuration().toInt()
                    updateProgressBufferingState()
                }

                else -> {
                    binding.loadingView.visibility = View.GONE
                    binding.disableClicksLayout.visibility = View.GONE
                }
            }
            updateProgressState()
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        meController?.removeListener(playerListener)
    }

    private fun updateProgressUi() {
        binding.sbProgress.value = 0f
        binding.progressBar.progress = 0
        binding.progressDurationTv.text = convertMillisToMinutesAndSecondsString(0L)
        binding.totalDurationTv.visibility = View.GONE
    }

    private fun updateInfoUi(mediaItem: MediaItem?) {
        if (mediaItem == null) {
            binding.playbackErrorLayout.visibility = View.VISIBLE
            return
        }

        Glide.with(this)
            .asBitmap()
            .load(mediaItem.mediaMetadata.artworkUri)
            .placeholder(R.mipmap.musicoo_logo_img)
            .into(object : CustomTarget<Bitmap>() {
                override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
                    binding.thumbnail.setImageBitmap(resource)
                    val blurredBitmap = applyGaussianBlur(resource, 25f, this@MoPlayDetailsActivity)
                    binding.imageView.setImageBitmap(blurredBitmap)
                }

                override fun onLoadCleared(placeholder: Drawable?) {
                    if (placeholder != null) {
                        binding.thumbnail.setImageDrawable(placeholder)
                    }
                }
            })

        binding.nameTv.text = mediaItem.mediaMetadata.title
        binding.descTv.text = mediaItem.mediaMetadata.artist
    }

    /**
     * 更新播放进度
     */
    private fun updateProgressState() {
        //判断是否ready与播放中，否则停止更新进度
        if (meController != null && meController.playbackState == Player.STATE_READY && meController.isPlaying) {
            updatePlayState(meController.isPlaying)
            progressHandler.removeCallbacksAndMessages(null)
            progressHandler.sendEmptyMessage(1)
        } else {
            progressHandler.removeCallbacksAndMessages(null)
        }
    }

    /**
     * 播放进度
     */
    private val progressHandler = object : Handler(Looper.myLooper()!!) {
        override fun handleMessage(msg: Message) {
            //判断是否ready与播放中，否则停止更新进度
            if (meController != null && meController.playbackState == Player.STATE_READY && meController.isPlaying) {
                val currentPosition = MediaControllerManager.getCurrentPosition()
                val currentString = convertMillisToMinutesAndSecondsString(currentPosition)
                binding.progressDurationTv.text = currentString

                val currentBufferedPosition = MediaControllerManager.getBufferedPosition()
                binding.progressBar.progress = currentBufferedPosition.toInt()

                // 更新 SeekBar 的进度
                binding.sbProgress.value = currentPosition.toFloat()

                sendEmptyMessageDelayed(1, 50)
            }
        }
    }

    /**
     * 更新缓冲进度
     */
    private fun updateProgressBufferingState() {
        if (meController != null && meController.isLoading) {
            progressBufferingHandler.removeCallbacksAndMessages(null)
            progressBufferingHandler.sendEmptyMessage(1)
        } else {
            progressBufferingHandler.removeCallbacksAndMessages(null)
        }
    }

    /**
     * 缓冲进度
     */
    private val progressBufferingHandler = object : Handler(Looper.myLooper()!!) {
        override fun handleMessage(msg: Message) {
            if (meController != null && meController.isLoading) {
                val currentBufferedPosition = MediaControllerManager.getBufferedPosition()
                binding.progressBar.progress = currentBufferedPosition.toInt()
                sendEmptyMessageDelayed(1, 50)
            }
        }
    }

    private fun updatePlayState(b: Boolean) {
        if (b) {
            binding.playImg.setImageResource(R.drawable.playing_green_icon)
        } else {
            binding.playImg.setImageResource(R.drawable.play_green_icon)
        }
    }


    private fun toggleBottomLayout() {
        if (binding.bottomLayout.visibility == View.VISIBLE) {
            hideBottomLayout()
        } else {
            showBottomLayout()
        }
    }

    private fun showBottomLayout() {
        val slideUpAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_up)
        binding.bottomLayout.startAnimation(slideUpAnimation)
        binding.bottomLayout.visibility = View.VISIBLE
    }

    private fun hideBottomLayout() {
        val slideDownAnimation = AnimationUtils.loadAnimation(this, R.anim.slide_down)
        binding.bottomLayout.startAnimation(slideDownAnimation)
        binding.bottomLayout.visibility = View.GONE
    }
}