package melody.offline.music.activity

import android.annotation.SuppressLint
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.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.OptIn
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
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.google.android.material.bottomsheet.BottomSheetDialog
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.LikedSongsAdapter
import melody.offline.music.ads.AdPlacement
import melody.offline.music.ads.LolAdWrapper
import melody.offline.music.bean.FavoriteBean
import melody.offline.music.databinding.ActivityLikedSongsBinding
import melody.offline.music.fragment.MoMeFragment
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 org.json.JSONObject

@OptIn(UnstableApi::class)
class MoLikedSongsActivity : MoBaseActivity(), LikedSongsAdapter.OnItemFavoritesClickListener,
    LikedSongsAdapter.OnMoreClickListener {

    private val requests: Channel<Request> = Channel(Channel.UNLIMITED)

    sealed class Request {
        data object TryAgain : Request()
        data class UpdateFavorite(val bean: FavoriteBean) : Request()
        data class OnFavorites(val bean: FavoriteBean) : Request()
        data class OnDownload(val favoriteBean: FavoriteBean) : Request()
        data class OnDownloadRemove(val id: String) : Request()
        data class OnUpdateDownloadUi(val id: String) : Request()
        data class OnAddPlaylist(val bean: FavoriteBean) : Request()
    }

    private lateinit var binding: ActivityLikedSongsBinding
    private var adapter: LikedSongsAdapter? = null
    private var favoriteBeans: MutableList<FavoriteBean> = mutableListOf()
    private var currentPosition = -1

    override suspend fun main() {
        binding = ActivityLikedSongsBinding.inflate(layoutInflater)
        setContentView(binding.root)
        LolAdWrapper.shared.showAdTiming(this, AdPlacement.INST_ME_PAGE_LIST)
        initImmersionBar()
        initView()
        initAdapter()
        LolAdWrapper.shared.loadAdIfNotCached(this, AdPlacement.INST_ME_PAGE_LIST)
        initDownloadFlow()
        initData()
        onReceive()
    }

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

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

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

                        is Request.OnFavorites -> {
                            it.bean.isFavorite = !it.bean.isFavorite
                            adapter?.notifyDataSetChanged()

                            updateFavoriteUi(it.bean.isFavorite)

                            val currentFavoriteBean =
                                App.appFavoriteDBManager.getFavoriteBeanByID(it.bean.videoId)
                            if (currentFavoriteBean != null) {
                                App.appFavoriteDBManager.updateFavoriteBean(it.bean)
                            }
                        }

                        is Request.OnDownload -> {
                            val id = it.favoriteBean.videoId
                            LogTag.LogD(TAG, "OnDownload id->${id}")
                            val currentOfflineBean = App.appOfflineDBManager.getOfflineBeanByID(id)
                            if (currentOfflineBean != null) {//判断当前数据库是否有这条数据。
                                if (currentPosition >= 0) {
                                    val videoId = favoriteBeans[currentPosition].videoId
                                    showRemoveDownloadDialogHint(videoId)
                                }
                            } else {
                                //判断是否已经下载了这条数据，已经下载，就直接进行数据库数据存储，反之走下载流程。
                                if (DownloadUtil.downloadResourceExist(id)) {
                                    insertOfflineData(it.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@MoLikedSongsActivity,
                                            getString(R.string.download_tips),
                                            Toast.LENGTH_LONG
                                        ).show()
                                    } else {
                                        DownloadService.sendAddDownload(
                                            this@MoLikedSongsActivity,
                                            MyDownloadService::class.java,
                                            downloadRequest,
                                            false
                                        )


                                        LolAdWrapper.shared.showAdTiming(
                                            this@MoLikedSongsActivity, AdPlacement.INST_DOWNLOAD
                                        )

                                        insertOfflineData(it.favoriteBean)
                                        val jsonObject = JSONObject()
                                        jsonObject.put(
                                            "download_id", "${it.favoriteBean.videoId}"
                                        )
                                        val songMap = mutableMapOf(
                                            Pair(
                                                AnalysisUtil.PARAM_VALUE, jsonObject.toString()
                                            )
                                        )
                                        AnalysisUtil.logEvent(
                                            AnalysisUtil.PLAYER_B_DOWNLOAD_CLICK, songMap
                                        )

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

                        is Request.OnDownloadRemove -> {
                            LogTag.LogD(TAG, "OnDownloadRemove id->${it.id}")
                            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 -> {
                            showAddPlaylistBottomDialog(it.bean)
                        }
                    }
                }
                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()
        }

        LolAdWrapper.shared.loadAdShowNativeAd(
            this,
            AdPlacement.NATIVE_ME_PAGE_LIST,
            binding.frameAd,
            R.layout.ad_layout_admob_banner,
            R.layout.ad_layout_max_banner
        )
    }

    private fun initView() {
        binding.layoutInfo.setOnClickListener { }
        binding.backBtn.setOnClickListener {
            finish()
        }
        binding.tryAgainBtn.setOnClickListener {
            requests.trySend(Request.TryAgain)
        }
        binding.bottomCloseBtn.setOnClickListener {
            hideBottomLayout()
        }
        binding.bottomBlankLayout.setOnClickListener {
            hideBottomLayout()
        }
        binding.favoritesBtn.setOnClickListener {
            if (currentPosition >= 0) {
                requests.trySend(Request.OnFavorites(favoriteBeans[currentPosition]))
            }
        }
        binding.moreDownloadBtn.setOnClickListener {
            if (currentPosition >= 0) {
                requests.trySend(Request.OnDownload(favoriteBeans[currentPosition]))
            }
        }
        binding.moreAddPlaylistBtn.setOnClickListener {
            if (currentPosition >= 0) {
                requests.trySend(Request.OnAddPlaylist(favoriteBeans[currentPosition]))
                hideBottomLayout()
            }
        }
    }

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

    private fun initAdapter() {
        adapter = LikedSongsAdapter(this, favoriteBeans)
        adapter?.setOnFavoritesItemClickListener(this)
        adapter?.setOnMoreClickListener(this)
        binding.rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        binding.rv.adapter = adapter
    }

    override fun onFavoritesItemClick(position: Int) {
        requests.trySend(Request.OnFavorites(favoriteBeans[position]))
    }

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

    private fun initDownloadFlow() {
        ViewModelMain.modelDownloadsFlow.observe(this) { downloads ->
            if (currentPosition >= 0) {
                val id = favoriteBeans[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 = favoriteBeans[position]
        Glide.with(this).load(bean.thumbnail).into(binding.songImg)
        binding.title.text = bean.title
        if (bean.name.isEmpty()) {
            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
    }

    @SuppressLint("NotifyDataSetChanged")
    private suspend fun initData() {
        showLoadingUi()
        favoriteBeans.clear()
        val beans = App.appFavoriteDBManager.getAllFavoriteBeans()
        val filteredBeans = beans.filter { it.isFavorite }
        favoriteBeans.addAll(filteredBeans)
        if (favoriteBeans.size > 0) {
            showDataUi()
        } else {
            showNoContentUi()
        }
        if (adapter != null) {
            adapter?.notifyDataSetChanged()
        }
    }

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