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.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.PlaylistItem
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 melody.offline.music.util.asMediaItem
import melody.offline.music.util.asPlaylistItem
import melody.offline.music.view.ListMoreBottomSheetDialog
import org.json.JSONObject

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

    sealed class Request {
        data object TryAgain : Request()
        data class UpdateFavorite(val bean: PlaylistItem) : Request()
        data class OnFavorites(val bean: PlaylistItem) : Request()
        data class OnDownload(val bean: PlaylistItem) : Request()
        data class OnDownloadRemove(val bean: PlaylistItem) : Request()
        data class OnUpdateDownloadUi(val bean: PlaylistItem) : Request()
        data class OnAddPlaylist(val bean: PlaylistItem) : Request()
        data class OnUpdateCurrentListItem(val bean: PlaylistItem) : 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 moreDialog: ListMoreBottomSheetDialog? = null

    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}")
        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)
                            }
                            requests.trySend(Request.OnUpdateCurrentListItem(it.bean))
                        }

                        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,
                                    name = it.bean.name,
                                    thumbnail = it.bean.thumbnail,
                                    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 offBean =
                                App.appOfflineDBManager.getOfflineBeanByID(id)//得到当前ID的本地数据
                            if (offBean != null && offBean.bytesDownloaded?.let { bytes -> bytes > 0 } == true) {//判断当前数据库是否有这条数据。
                                showRemoveDownloadDialogHint(it.bean)
                            } else {
                                val isFavorite =
                                    App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId)
                                //判断是否已经下载了这条数据，已经下载，就直接进行数据库数据存储，反之走下载流程。
                                if (DownloadUtil.downloadResourceExist(id)) {
                                    val favoriteBean = FavoriteBean(
                                        id,
                                        it.bean.title,
                                        it.bean.name,
                                        it.bean.thumbnail,
                                        isFavorite?.isFavorite ?: false
                                    )
                                    insertOfflineData(favoriteBean)
                                    it.bean.isOffline = true//更改状态
                                    requests.trySend(Request.OnUpdateDownloadUi(it.bean))
                                    requests.trySend(Request.OnUpdateCurrentListItem(it.bean))
                                } 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,
                                            it.bean.name,
                                            it.bean.thumbnail,
                                            isFavorite?.isFavorite ?: false
                                        )
                                        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.bean.videoId)
                            if (currentOfflineBean != null) {
                                App.appOfflineDBManager.deleteOfflineBean(currentOfflineBean)

                                it.bean.isOffline = false
                            }
                            requests.trySend(Request.OnUpdateDownloadUi(it.bean))
                            requests.trySend(Request.OnUpdateCurrentListItem(it.bean))
                        }

                        is Request.OnUpdateDownloadUi -> {
                            moreDialog?.updateDownloadBtnUi(it.bean.isOffline)//更新对话框的ui
                        }

                        is Request.OnAddPlaylist -> {
                            val isFavorite =
                                App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId) != null
                            showAddPlaylistBottomDialog(
                                FavoriteBean(
                                    videoId = it.bean.videoId,
                                    title = it.bean.title,
                                    name = it.bean.name,
                                    thumbnail = it.bean.thumbnail,
                                    isFavorite
                                )
                            )
                        }

                        is Request.OnUpdateCurrentListItem -> {
                            //更新数据集合当前的item数据
                            updateCurrentItem(it.bean.videoId)
                        }
                    }
                }
                events.onReceive {
                    when (it) {
                        Event.ActivityOnResume -> {
                            activityOnResume()
                        }

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

                        else -> {}
                    }
                }
            }
        }
    }

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

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

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


    override fun onItemDownloadClick(position: Int) {

    }

    override fun onItemMoreClick(position: Int) {
        val bean = myList[position]
        LogD(TAG, "MoListDetailsActivity onItemMoreClick -> ${bean.asPlaylistItem}")
        moreDialog = ListMoreBottomSheetDialog(
            this@MoListDetailsActivity,
            bean.asPlaylistItem,
            this@MoListDetailsActivity,
            this@MoListDetailsActivity
        )
        moreDialog?.setListMoreViewListener(this@MoListDetailsActivity)
        moreDialog?.show()
    }


    override fun onFavoritesClicked(playlistItem: PlaylistItem) {
        requests.trySend(Request.OnFavorites(playlistItem))
    }

    override fun onDownloadClicked(playlistItem: PlaylistItem) {
        requests.trySend(Request.OnDownload(playlistItem))
    }

    override fun onAddToPlaylistClicked(playlistItem: PlaylistItem) {
        requests.trySend(Request.OnAddPlaylist(playlistItem))
    }

    @SuppressLint("NotifyDataSetChanged")
    override fun onUpdateAdapterListener(download: Download, playlistItem: PlaylistItem) {
        requests.trySend(Request.OnUpdateCurrentListItem(playlistItem))
    }

    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)
            }
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    private suspend fun initData(browseId: String) {
        showLoadingUi()
        Innertube.moPlaylistPage(browseId)?.onSuccess {
            if (this.isDestroyed || this.isFinishing) {
                return
            }
            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

                val mapList = it.moPlaylistOrAlbumListBean.map { item ->
                    val offlineBean = App.appOfflineDBManager.getOfflineBeanByID(item.videoId?:"")
                    val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(item.videoId?:"")
                    var isOffline = false
                    var bytesDownloaded = 0L
                    var size = ""
                    if (offlineBean != null) {
                        isOffline = offlineBean.isOffline
                        bytesDownloaded = offlineBean.bytesDownloaded ?: 0L
                        size = offlineBean.size ?: ""
                    }
                    var isFavorite = false
                    if (favoriteBean != null) {
                        isFavorite = favoriteBean.isFavorite
                    }
                    item.copy(
                        isOffline = isOffline,
                        isFavorite = isFavorite,
                        bytesDownloaded = bytesDownloaded,
                        size = size
                    )
                }

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

    private suspend fun updateCurrentItem(id: String) {
        //更新当前界面的数据集合
        myList.forEach { item ->
            if (item.videoId == id) {
                val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(item.videoId)
                val offlineBean = App.appOfflineDBManager.getOfflineBeanByID(item.videoId)
                item.isFavorite = favoriteBean?.isFavorite ?: false
                item.isOffline = offlineBean?.isOffline ?: false
                item.bytesDownloaded = offlineBean?.bytesDownloaded
                item.size = offlineBean?.size
            }
        }
        myList.forEach { item ->
            if (item.videoId == id) {
                LogD(TAG, "updateCurrentItem -> $item")
            }
        }
    }

    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 updateFavoriteUi(b: Boolean) {
        if (moreDialog != null) {
            moreDialog?.updateFavoriteUi(b)
        }
    }

    private fun showRemoveDownloadDialogHint(playlistItem: PlaylistItem) {
        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(playlistItem))
        }
        cancelBtn.setOnClickListener {
            dialog.dismiss()
        }
    }

}