package melody.offline.music.activity

import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View
import android.view.animation.AnimationUtils
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.OptIn
import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.offline.Download
import androidx.media3.exoplayer.offline.DownloadRequest
import androidx.media3.exoplayer.offline.DownloadService
import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.gyf.immersionbar.ktx.immersionBar
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.selects.select
import melody.offline.music.App
import melody.offline.music.R
import melody.offline.music.adapter.DetailsListAdapter
import melody.offline.music.ads.AdPlacement
import melody.offline.music.ads.LolAdWrapper
import melody.offline.music.bean.FavoriteBean
import melody.offline.music.bean.OfflineBean
import melody.offline.music.databinding.ActivityDetailsBinding
import melody.offline.music.innertube.Innertube
import melody.offline.music.innertube.requests.moPlaylistPage
import melody.offline.music.service.MyDownloadService
import melody.offline.music.service.ViewModelMain
import melody.offline.music.util.AnalysisUtil
import melody.offline.music.util.DownloadUtil
import melody.offline.music.util.LogTag
import melody.offline.music.util.LogTag.LogD
import org.json.JSONObject

@OptIn(UnstableApi::class)
class MoListDetailsActivity : MoBaseActivity(), DetailsListAdapter.OnItemMoreClickListener,
    DetailsListAdapter.OnItemDownloadClickListener {
    private val requests: Channel<Request> = Channel(Channel.UNLIMITED)

    sealed class Request {
        data object TryAgain : Request()
        data class UpdateFavorite(val bean: Innertube.MoPlaylistOrAlbumPage.MoPlaylistOrAlbumListBean) :
            Request()

        data class OnFavorites(
            val bean: Innertube.MoPlaylistOrAlbumPage.MoPlaylistOrAlbumListBean, val imgUrl: String
        ) : Request()

        data class OnDownload(
            val bean: Innertube.MoPlaylistOrAlbumPage.MoPlaylistOrAlbumListBean, val imgUrl: String
        ) : Request()

        data class OnDownloadRemove(val id: String) : Request()
        data class OnUpdateDownloadUi(val id: String) : Request()
        data class OnAddPlaylist(
            val bean: Innertube.MoPlaylistOrAlbumPage.MoPlaylistOrAlbumListBean,
            val imgUrl: String
        ) :
            Request()
    }

    companion object {
        const val PLAY_LIST_PAGE_BROWSE_ID = "play_list_page_browse_id"
    }

    private lateinit var binding: ActivityDetailsBinding
    private var browseId: String? = null

    private var adapter: DetailsListAdapter? = null
    private var myList: MutableList<Innertube.MoPlaylistOrAlbumPage.MoPlaylistOrAlbumListBean> =
        mutableListOf()
    private var myBean: Innertube.MoPlaylistOrAlbumPage? = null
    private var currentPosition = -1
    override suspend fun main() {
        binding = ActivityDetailsBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initImmersionBar()
        browseId = intent.getStringExtra(PLAY_LIST_PAGE_BROWSE_ID)
        if (browseId.isNullOrEmpty() || browseId == "null") {
            finish()
            return
        }
        initView()
        LogD(TAG, "browseId->${browseId}")
        initDownloadFlow()
        initData(browseId!!)
        onReceive()
    }

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

    @SuppressLint("NotifyDataSetChanged")
    private suspend fun onReceive() {
        while (isActive) {
            select<Unit> {
                requests.onReceive {
                    when (it) {
                        Request.TryAgain -> {
                            initData(browseId!!)
                        }

                        is Request.UpdateFavorite -> {
                            val currentFavoriteBean =
                                App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId!!)
                            if (currentFavoriteBean != null) {
                                updateFavoriteUi(currentFavoriteBean.isFavorite)
                            } else {
                                updateFavoriteUi(false)
                            }
                        }

                        is Request.OnFavorites -> {
                            val jsonObject = JSONObject()
                            jsonObject.put(
                                "song_title", it.bean.title
                            )
                            val songMap = mutableMapOf(
                                Pair(
                                    AnalysisUtil.PARAM_VALUE, jsonObject.toString()
                                )
                            )
                            val currentFavoriteBean =
                                App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId!!)
                            if (currentFavoriteBean != null) {
                                currentFavoriteBean.isFavorite = !currentFavoriteBean.isFavorite
                                App.appFavoriteDBManager.updateFavoriteBean(currentFavoriteBean)
                                if (currentFavoriteBean.isFavorite) {
                                    AnalysisUtil.logEvent(
                                        AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap
                                    )
                                } else {
                                    AnalysisUtil.logEvent(
                                        AnalysisUtil.PLAYER_B_UN_LOVE_CLICK, songMap
                                    )
                                }
                            } else {
                                val b = FavoriteBean(
                                    videoId = it.bean.videoId,
                                    title = it.bean.title.toString(),
                                    name = it.bean.name.toString(),
                                    thumbnail = it.bean.thumbnailUrl ?: it.imgUrl,
                                    isFavorite = true
                                )
                                App.appFavoriteDBManager.insertFavoriteBean(b)
                                AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_LOVE_CLICK, songMap)
                            }
                            requests.trySend(Request.UpdateFavorite(it.bean))
                        }

                        is Request.OnDownload -> {
                            val id = it.bean.videoId
                            val currentOfflineBean =
                                App.appOfflineDBManager.getOfflineBeanByID(id!!)
                            if (currentOfflineBean != null) {//判断当前数据库是否有这条数据。
                                if (currentPosition >= 0) {
                                    showRemoveDownloadDialogHint(id)
                                }
                            } else {
                                val isFavorite =
                                    App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId.toString()) != null
                                //判断是否已经下载了这条数据，已经下载，就直接进行数据库数据存储，反之走下载流程。
                                if (DownloadUtil.downloadResourceExist(id)) {
                                    val favoriteBean = FavoriteBean(
                                        id,
                                        it.bean.title.toString(),
                                        it.bean.name.toString(),
                                        it.bean.thumbnailUrl ?: it.imgUrl,
                                        isFavorite
                                    )
                                    insertOfflineData(favoriteBean)
                                    requests.trySend(Request.OnUpdateDownloadUi(id))
                                } else {
                                    val downloadRequest = DownloadRequest.Builder(id, id.toUri())
                                        .setCustomCacheKey(id).build()

                                    val downloadCount = DownloadUtil.getCurrentDownloads()
                                    if (downloadCount >= 3) {
                                        Toast.makeText(
                                            this@MoListDetailsActivity,
                                            getString(R.string.download_tips),
                                            Toast.LENGTH_LONG
                                        ).show()
                                    } else {
                                        DownloadService.sendAddDownload(
                                            this@MoListDetailsActivity,
                                            MyDownloadService::class.java,
                                            downloadRequest,
                                            false
                                        )

                                        LolAdWrapper.shared.showAdTiming(
                                            this@MoListDetailsActivity, AdPlacement.INST_DOWNLOAD
                                        )
                                        val favoriteBean = FavoriteBean(
                                            id,
                                            it.bean.title.toString(),
                                            it.bean.name.toString(),
                                            it.bean.thumbnailUrl ?: it.imgUrl,
                                            isFavorite
                                        )
                                        insertOfflineData(favoriteBean)
                                        val jsonObject = JSONObject()
                                        jsonObject.put(
                                            "download_id", favoriteBean.videoId
                                        )
                                        val songMap = mutableMapOf(
                                            Pair(
                                                AnalysisUtil.PARAM_VALUE, jsonObject.toString()
                                            )
                                        )
                                        AnalysisUtil.logEvent(
                                            AnalysisUtil.PLAYER_B_DOWNLOAD_CLICK, songMap
                                        )

                                        LolAdWrapper.shared.loadAdIfNotCached(
                                            this@MoListDetailsActivity, AdPlacement.INST_DOWNLOAD
                                        )
                                    }
                                }
                            }
                        }

                        is Request.OnDownloadRemove -> {
                            val currentOfflineBean =
                                App.appOfflineDBManager.getOfflineBeanByID(it.id)
                            if (currentOfflineBean != null) {
                                App.appOfflineDBManager.deleteOfflineBean(currentOfflineBean)
                            }

                            requests.trySend(Request.OnUpdateDownloadUi(it.id))
                        }

                        is Request.OnUpdateDownloadUi -> {
                            if (App.appOfflineDBManager.getOfflineBeanByID(it.id) != null) {
                                binding.downloadImg.setImageResource(R.drawable.more_downloaded_icon)
                                binding.downloadTv.text =
                                    getString(R.string.download_remove_offline)
                            } else {
                                binding.downloadImg.setImageResource(R.drawable.more_download_icon)
                                binding.downloadTv.text = getString(R.string.download_save_offline)
                            }
                        }

                        is Request.OnAddPlaylist -> {
                            val isFavorite =
                                App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId.toString()) != null
                            showAddPlaylistBottomDialog(
                                FavoriteBean(
                                    videoId = it.bean.videoId.toString(),
                                    title = it.bean.title.toString(),
                                    name = it.bean.name.toString(),
                                    thumbnail = it.bean.thumbnailUrl ?: it.imgUrl,
                                    isFavorite
                                )
                            )
                        }
                    }
                }
                events.onReceive {
                    when (it) {
                        Event.ActivityOnResume -> {
                            activityOnResume()
                        }

                        Event.AutomaticallySwitchSongs -> {
                            if (adapter != null) {
                                adapter?.notifyDataSetChanged()
                            }
                        }

                        else -> {}
                    }
                }
            }
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    private fun activityOnResume() {
        addMusicPlayerViewToLayout(binding.playMusicLayout)

        if (adapter != null) {
            adapter?.notifyDataSetChanged()
        }
    }


    override fun onItemDownloadClick(position: Int) {

    }

    override fun onItemMoreClick(position: Int) {
        currentPosition = position
        toggleBottomLayout(position)
    }

    private fun initView() {
        adapter = DetailsListAdapter(this, myList)
        adapter?.setOnItemDownloadClickListener(this)
        adapter?.setOnItemMoreClickListener(this)
        binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        binding.rv.adapter = adapter

        binding.backBtn.setOnClickListener {
            finish()
        }
        binding.tryAgainBtn.setOnClickListener {
            requests.trySend(Request.TryAgain)
        }
        binding.playAllBtn.setOnClickListener {
            if (myList.isNotEmpty()) {
                val bean = myList[0]
                val intent = Intent(this, MoPlayDetailsActivity::class.java)
                intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_VIDEO_ID, bean.videoId)
                intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_PLAY_LIST_ID, bean.playlistId)
                intent.putExtra(
                    MoPlayDetailsActivity.PLAY_DETAILS_PLAY_LIST_SET_VIDEO_ID,
                    bean.playlistSetVideoId
                )
                intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_PLAY_PARAMS, bean.params)

                intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_NAME, bean.title)
                intent.putExtra(MoPlayDetailsActivity.PLAY_DETAILS_DESC, bean.name)
                startActivity(intent)
            }
        }
        binding.layoutInfo.setOnClickListener { }

        binding.bottomCloseBtn.setOnClickListener {
            hideBottomLayout()
        }
        binding.bottomBlankLayout.setOnClickListener {
            hideBottomLayout()
        }
        binding.favoritesBtn.setOnClickListener {
            if (currentPosition >= 0) {
                requests.trySend(
                    Request.OnFavorites(
                        myList[currentPosition],
                        myBean?.thumbnail.toString()
                    )
                )
            }
        }
        binding.moreDownloadBtn.setOnClickListener {
            if (currentPosition >= 0) {
                requests.trySend(
                    Request.OnDownload(
                        myList[currentPosition],
                        myBean?.thumbnail.toString()
                    )
                )
            }
        }
        binding.moreAddPlaylistBtn.setOnClickListener {
            if (currentPosition >= 0) {
                requests.trySend(
                    Request.OnAddPlaylist(
                        myList[currentPosition],
                        myBean?.thumbnail.toString()
                    )
                )
                hideBottomLayout()
            }
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    private suspend fun initData(browseId: String) {
        showLoadingUi()
        Innertube.moPlaylistPage(browseId)?.onSuccess {
            if (this.isDestroyed || this.isFinishing) {
                return
            }
            myBean = it
            LogD(TAG, "moPlaylistPage onSuccess->${it.moPlaylistOrAlbumListBean}")
            if (it.moPlaylistOrAlbumListBean.isNotEmpty()) {
                showDataUi()
                Glide.with(this).load(it.thumbnail).into(binding.imageView)

                binding.infoTitle.text = it.title
                binding.subtitle.text = it.subtitle
                binding.secondSubtitle.text = it.secondSubtitle

                myList.clear()
                myList.addAll(it.moPlaylistOrAlbumListBean)
                adapter?.notifyDataSetChanged()
            } else {
                showNoContentUi()
            }
        }?.onFailure {
            showNoContentUi()
            LogD(TAG, "moPlaylistPage onFailure->${it}")
        }
    }

    private fun showDataUi() {
        binding.loadingLayout.visibility = View.GONE
        binding.noContentLayout.visibility = View.GONE
    }

    private fun showLoadingUi() {
        binding.loadingLayout.visibility = View.VISIBLE
        binding.noContentLayout.visibility = View.GONE
    }

    private fun showNoContentUi() {
        binding.loadingLayout.visibility = View.GONE
        binding.noContentLayout.visibility = View.VISIBLE
    }


    private fun initDownloadFlow() {
        ViewModelMain.modelDownloadsFlow.observe(this) { downloads ->
            if (currentPosition >= 0) {
                val id = myList[currentPosition].videoId
                val currentScreenDownloads = downloads[id]
                if (currentScreenDownloads != null) {
                    updateDownloadUI(currentScreenDownloads)
                }
            }
        }
    }

    private fun updateDownloadUI(download: Download) {
        when (download.state) {
            Download.STATE_DOWNLOADING -> {
                binding.downloadLoading.visibility = View.VISIBLE
                binding.downloadImg.setImageResource(R.drawable.more_download_icon)
                binding.downloadImg.visibility = View.GONE

                binding.downloadTv.text = getString(R.string.download_saving)

                binding.moreDownloadBtn.isClickable = false
                binding.moreDownloadBtn.isEnabled = false
            }

            Download.STATE_COMPLETED -> {
                binding.downloadLoading.visibility = View.GONE
                binding.downloadImg.setImageResource(R.drawable.more_downloaded_icon)
                binding.downloadImg.visibility = View.VISIBLE

                binding.downloadTv.text = getString(R.string.download_remove_offline)

                binding.moreDownloadBtn.isClickable = true
                binding.moreDownloadBtn.isEnabled = true

                val jsonObject = JSONObject()
                jsonObject.put(
                    "download_id", download.request.id
                )
                val songMap = mutableMapOf(
                    Pair(
                        AnalysisUtil.PARAM_VALUE, jsonObject.toString()
                    )
                )
                AnalysisUtil.logEvent(AnalysisUtil.PLAYER_B_DOWNLOAD_SUCCESS_ACTION, songMap)
            }

            Download.STATE_FAILED -> {
                binding.downloadLoading.visibility = View.GONE
                binding.downloadImg.setImageResource(R.drawable.error)
                binding.downloadImg.visibility = View.VISIBLE

                binding.downloadTv.text = getString(R.string.download_save_offline)

                binding.moreDownloadBtn.isClickable = true
                binding.moreDownloadBtn.isEnabled = true
            }

            else -> {
                binding.downloadLoading.visibility = View.GONE
                binding.downloadImg.setImageResource(R.drawable.more_download_icon)
                binding.downloadImg.visibility = View.VISIBLE

                binding.downloadTv.text = getString(R.string.download_save_offline)

                binding.moreDownloadBtn.isClickable = true
                binding.moreDownloadBtn.isEnabled = true
            }
        }
    }

    private fun updateFavoriteUi(b: Boolean) {
        if (b) {
            binding.favoritesImg.setImageResource(R.drawable.favorited_icon)
        } else {
            binding.favoritesImg.setImageResource(R.drawable.not_favorited_icon)
        }
    }

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

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

        val bean = myList[position]
        val imgUrl = bean.thumbnailUrl ?: myBean?.thumbnail
        Glide.with(this).load(imgUrl).into(binding.songImg)
        binding.title.text = bean.title
        if (bean.name?.isEmpty() == true) {
            binding.name.visibility = View.GONE
        } else {
            binding.name.visibility = View.VISIBLE
            binding.name.text = bean.name
        }
        requests.trySend(Request.UpdateFavorite(bean))

        requests.trySend(Request.OnUpdateDownloadUi(bean.videoId!!))

        val currentDownload = DownloadUtil.getCurrentIdDownload(bean.videoId)
        if (currentDownload != null) {
            updateDownloadUI(currentDownload)
        }
    }

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

    private fun showRemoveDownloadDialogHint(id: String) {
        val inflater = LayoutInflater.from(this)
        val dialogView = inflater.inflate(R.layout.dialog_hint, null)
        val okBtn = dialogView.findViewById<TextView>(R.id.dialog_ok_btn)
        val cancelBtn = dialogView.findViewById<TextView>(R.id.dialog_cancel_btn)
        val dialogBuilder = AlertDialog.Builder(this).setView(dialogView)
        val dialog = dialogBuilder.create()
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        dialog.show()
        okBtn.setOnClickListener {
            dialog.dismiss()
            requests.trySend(Request.OnDownloadRemove(id))
        }
        cancelBtn.setOnClickListener {
            dialog.dismiss()
        }
    }

}