package melody.offline.music.activity

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicBlur
import android.view.LayoutInflater
import android.view.View
import android.widget.EditText
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.ProgressBar
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.OptIn
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.lifecycle.LifecycleOwner
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
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 androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.ironsource.be
import com.ironsource.vi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.selects.select
import kotlinx.coroutines.withContext
import melody.offline.music.App
import melody.offline.music.R
import melody.offline.music.adapter.NewPlayListAdapter
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.bean.Playlist
import melody.offline.music.bean.PlaylistItem
import melody.offline.music.http.getAppVersionCode
import melody.offline.music.http.getCountryCode
import melody.offline.music.innertube.Innertube
import melody.offline.music.media.MediaControllerManager
import melody.offline.music.service.MyDownloadService
import melody.offline.music.service.ViewModelMain
import melody.offline.music.sp.AppStore
import melody.offline.music.util.AnalysisUtil
import melody.offline.music.util.DownloadUtil
import melody.offline.music.util.FileSizeConverter
import melody.offline.music.util.LogTag
import melody.offline.music.view.MusicPlayerView
import melody.offline.music.view.RatingDialog
import org.json.JSONObject
import java.util.concurrent.TimeUnit


@OptIn(UnstableApi::class)
abstract class MoBaseActivity : AppCompatActivity(), MusicPlayerView.PlaySkipForwardListener,
    CoroutineScope by MainScope(), LifecycleOwner {
    private var playerListener: Player.Listener? = null
    private var currentLayoutId: LinearLayout? = null

    enum class Event {
        ActivityStart, ActivityStop, ActivityOnResume, AutomaticallySwitchSongs,
    }

    protected val TAG = LogTag.VO_ACT_LOG
    protected val appStore by lazy { AppStore(this) }
    protected val events = Channel<Event>(Channel.UNLIMITED)
    protected val meController = MediaControllerManager.getController()
    protected abstract suspend fun main()
    private var defer: suspend () -> Unit = {}
    private var deferRunning = false
    private lateinit var musicPlayerView: MusicPlayerView

    fun defer(operation: suspend () -> Unit) {
        this.defer = operation
    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        musicPlayerView = MusicPlayerView(this, meController, this)
        initPlayerListener()
        launch {
            main()
        }
    }

    override fun onResume() {
        super.onResume()
        events.trySend(Event.ActivityOnResume)
    }

    override fun onStart() {
        super.onStart()
        events.trySend(Event.ActivityStart)
    }

    override fun onStop() {
        super.onStop()
        events.trySend(Event.ActivityStop)
    }

    override fun finish() {
        if (deferRunning) {
            return
        }

        deferRunning = true

        launch {
            try {
                defer()
            } finally {
                withContext(NonCancellable) {
                    super.finish()
                }
            }
        }
    }

    fun addMusicPlayerViewToLayout(layoutId: LinearLayout?) {
        if (layoutId == null) {
            return
        }
        currentLayoutId = layoutId
        if (meController != null && meController.mediaItemCount > 0 && meController.duration > 0) {
            if (layoutId.childCount <= 0) {//没有添加view才进行添加
                layoutId.addView(musicPlayerView)
            }
            musicPlayerView.updateInfoUi(meController.currentMediaItem)
            musicPlayerView.updateSetProgress(meController)
            musicPlayerView.updateProgressState(meController)
            layoutId.visibility = View.VISIBLE
        } else {
            layoutId.visibility = View.GONE
        }
    }

    private fun initPlayerListener() {
        if (this !is MoPlayDetailsActivity && this !is LaunchActivity) {
            if (playerListener == null) {
                LogTag.LogD(TAG, "MoBaseActivity initPlayerListener")
                meController?.addListener(getPlayerListener())
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (meController != null && playerListener != null) {
            meController.removeListener(playerListener!!)
        }
    }

    private fun getPlayerListener(): Player.Listener {
        if (playerListener == null) {
            playerListener = object : Player.Listener {

                override fun onPositionDiscontinuity(
                    oldPosition: Player.PositionInfo, newPosition: Player.PositionInfo, reason: Int
                ) {
                    LogTag.LogD(TAG, "reason->$reason")
                    if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION || reason == Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT) {
                        if (meController != null) {
                            musicPlayerView.updateInfoUi(meController.currentMediaItem)
                            musicPlayerView.updateSetProgress(meController)
                            musicPlayerView.updateProgressState(meController)
                        }
                        LogTag.LogD(TAG, "reason update")
                        events.trySend(Event.AutomaticallySwitchSongs)
                    }
                }

                override fun onPlaybackStateChanged(playbackState: Int) {
                    val meController = MediaControllerManager.getController()
                    if (meController != null) {
                        musicPlayerView.updateProgressState(meController)

                        when (playbackState) {
                            Player.STATE_IDLE -> {
                                LogTag.LogD(TAG, "base STATE_IDLE")
                            }

                            Player.STATE_BUFFERING -> {
                                LogTag.LogD(TAG, "base STATE_BUFFERING")
                            }

                            Player.STATE_READY -> {
                                LogTag.LogD(TAG, "base STATE_READY")
                                musicPlayerView.updateSetProgress(meController)
                                //在加载的时候突然回到上一个界面，onResume会无法进入显示的判断
                                //防止悬浮框消失
                                if (currentLayoutId != null) {
                                    addMusicPlayerViewToLayout(currentLayoutId)
                                }
                            }

                            else -> {}
                        }
                    }
                }

                override fun onPlayWhenReadyChanged(
                    playWhenReady: Boolean, reason: Int
                ) {
                    LogTag.LogD(TAG, "base onPlayWhenReadyChanged $playWhenReady")
                    musicPlayerView.updatePlayState(playWhenReady)
                    val meController = MediaControllerManager.getController()
                    if (meController != null) {
                        musicPlayerView.updateProgressState(meController)
                    }

                }
            }
        }
        return playerListener!!
    }

    fun applyGaussianBlur(inputBitmap: Bitmap, radius: Float, context: Context): Bitmap {
        val rsContext = RenderScript.create(context)
        val outputBitmap =
            Bitmap.createBitmap(inputBitmap.width, inputBitmap.height, inputBitmap.config)
        val blurScript = ScriptIntrinsicBlur.create(rsContext, Element.U8_4(rsContext))
        val tmpIn = Allocation.createFromBitmap(rsContext, inputBitmap)
        val tmpOut = Allocation.createFromBitmap(rsContext, outputBitmap)
        blurScript.setRadius(radius)
        blurScript.setInput(tmpIn)
        blurScript.forEach(tmpOut)
        tmpOut.copyTo(outputBitmap)
        rsContext.finish()
        return outputBitmap
    }

    fun showSongDescriptionDialog(description: String) {
        val inflater = LayoutInflater.from(this)
        val dialogView = inflater.inflate(R.layout.dialog_description, null)
        val title = dialogView.findViewById<TextView>(R.id.dialog_title)
        title.text = getString(R.string.description)
        val content = dialogView.findViewById<TextView>(R.id.dialog_content)
        content.text = description
        val close = dialogView.findViewById<RelativeLayout>(R.id.closeBtn)
        val dialogBuilder = AlertDialog.Builder(this).setView(dialogView)
        val dialog = dialogBuilder.create()
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        dialog.show()
        close.setOnClickListener {
            dialog.dismiss()
        }
    }

    fun extractTextBeforeNewline(text: String): String {
        // 用换行符分割文本，取第一个部分
        return text.split("\n\n")[0]
    }


    suspend fun insertOfflineData(mediaItem: MediaItem) {
        val currentDownload = DownloadUtil.getCurrentIdDownload(mediaItem.mediaId)
        val favoriteBean = App.appFavoriteDBManager.getFavoriteBeanByID(mediaItem.mediaId)
        val bean = OfflineBean(
            videoId = mediaItem.mediaId,
            title = mediaItem.mediaMetadata.title.toString(),
            name = mediaItem.mediaMetadata.artist.toString(),
            thumbnail = mediaItem.mediaMetadata.artworkUri.toString(),
            isOffline = true,
            isFavorite = favoriteBean?.isFavorite ?: false,
            bytesDownloaded = currentDownload?.bytesDownloaded,
            size = FileSizeConverter.formatSize(currentDownload?.bytesDownloaded ?: 0)
        )
        LogTag.LogD(TAG, "insertOfflineBean bean->${bean}")
        App.appOfflineDBManager.insertOfflineBean(bean)
    }

    suspend fun insertOfflineData(favoriteBean: FavoriteBean) {
        val currentDownload = DownloadUtil.getCurrentIdDownload(favoriteBean.videoId)
        if (currentDownload != null) {
            val bytesDownloaded = currentDownload.bytesDownloaded
            val size = FileSizeConverter(currentDownload.bytesDownloaded).formattedSize()
            val bean = OfflineBean(
                videoId = favoriteBean.videoId,
                title = favoriteBean.title,
                name = favoriteBean.name,
                thumbnail = favoriteBean.thumbnail,
                isOffline = true,
                isFavorite = favoriteBean.isFavorite,
                bytesDownloaded = bytesDownloaded,
                size = size
            )
            App.appOfflineDBManager.insertOfflineBean(bean)
        } else {
            val bean = OfflineBean(
                videoId = favoriteBean.videoId,
                title = favoriteBean.title,
                name = favoriteBean.name,
                thumbnail = favoriteBean.thumbnail,
                isOffline = true,
                isFavorite = favoriteBean.isFavorite,
            )
            App.appOfflineDBManager.insertOfflineBean(bean)
        }
    }

    suspend fun insertFavoriteData(mediaItem: MediaItem) {
        val bean = FavoriteBean(
            videoId = mediaItem.mediaId,
            title = mediaItem.mediaMetadata.title.toString(),
            name = mediaItem.mediaMetadata.artist.toString(),
            thumbnail = mediaItem.mediaMetadata.artworkUri.toString(),
            isFavorite = true
        )
        LogTag.LogD(TAG, "insertFavoriteBean bean->${bean}")
        App.appFavoriteDBManager.insertFavoriteBean(bean)
    }

    suspend fun insertFavoriteData(offlineBean: OfflineBean) {
        val bean = FavoriteBean(
            videoId = offlineBean.videoId,
            title = offlineBean.title,
            name = offlineBean.name,
            thumbnail = offlineBean.thumbnail,
            isFavorite = true
        )
        LogTag.LogD(TAG, "insertFavoriteBean bean->${bean}")
        App.appFavoriteDBManager.insertFavoriteBean(bean)
    }

    fun withPermission(): Boolean {
        //先判断当前配置的开关是否为true，为false的话就直接进入A
        val jsonString = appStore.shouldEnterMusicPageJson//得到配置的json
        LogTag.LogD(TAG, "withPermission jsonString->${jsonString}")
        val json = JSONObject(jsonString)
        val versionCode = json.optInt("versionCode")//得到配置的code
        val enter = json.optBoolean("enter")//得到配置的开关
        val currentVersionCode = getAppVersionCode(this)//得到当前应用的code
        //如果配置的code 等于 当前app的code，则把配置赋值给shouldEnterMusicPage
        if (versionCode.toLong() == currentVersionCode) {
            appStore.shouldEnterMusicPage = enter
        } else {
            appStore.shouldEnterMusicPage = true
        }
        LogTag.LogD(TAG, "withPermission shouldEnterMusicPage->${appStore.shouldEnterMusicPage}")
        return appStore.shouldEnterMusicPage
//        // 不允许的国家代码
//        val restrictedCountries = setOf(
////            "CN",
//            "HK",
//            "TW",
//            "JP",
//            "KR",
////            "GB",
////            "CH",
////            "BE",
////            "MO",
////            "SG"
//        )
//        // 检查是否包含当前的国家代码
//        LogTag.LogD(TAG, "withPermission ipCountryCode->${appStore.ipCountryCode}")
//        if (appStore.ipCountryCode in restrictedCountries) {
//            return false
//        }
//        // 如果不在受限国家代码中，则继续其他检查
//        return withIso()
    }

    private fun withIso(): Boolean {
        //460 || 461 China (People's Republic of)
        //454 "Hong Kong, China"
        //466 "Taiwan, China"
        //440 || 441 Japan
        //450 Korea (Republic of)
        //234 || 235 United Kingdom of Great Britain and Northern Ireland
        //228 Switzerland (Confederation of)
        //206 Belgium
        //455 "Macao, China"
        //525 Singapore (Republic of)
        val restrictedCountryCodes = setOf(
//                "460",
//                "461",
            "454",
            "466",
            "440",
            "441",
            "450",
//            "234", "235", "228", "206", "455", "525"
        )
        val currentCountryCode = getCountryCode(this)
        LogTag.LogD(TAG, "withPermission currentCountryCode->${currentCountryCode}")
        return currentCountryCode !in restrictedCountryCodes
    }

    suspend fun showAddPlaylistBottomDialog(favoriteBean: FavoriteBean) {
        val bottomAddPlaylistSheetDialog = BottomSheetDialog(this)
        val view = layoutInflater.inflate(R.layout.add_playlist_layout, null)
        bottomAddPlaylistSheetDialog.setContentView(view)
        val newPlayListBtn = view.findViewById<LinearLayout>(R.id.newPlayListBtn)
        val rv = view.findViewById<RecyclerView>(R.id.newPlayListRv)
        newPlayListBtn.setOnClickListener {
            bottomAddPlaylistSheetDialog.dismiss()
            showNewPlaylistBottomDialog(favoriteBean)
        }
        // 设置对话框背景为透明以显示圆角
        bottomAddPlaylistSheetDialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
        bottomAddPlaylistSheetDialog.window?.navigationBarColor =
            ContextCompat.getColor(this, R.color.main_bg_color)
        bottomAddPlaylistSheetDialog.show()

        val playlist = (App.appPlaylistDBManager.getAllPlaylists())
        val adapter = NewPlayListAdapter(this, playlist)
        adapter.setOnItemClickListener(object : NewPlayListAdapter.OnItemClickListener {
            override fun onItemClick(position: Int) {
                launch {
                    val playlistItem =
                        App.appPlaylistDBManager.getPlaylistItems(playlist[position].id)
                    val isAny = playlistItem.any { it.title == favoriteBean.title }
                    if (isAny) {//如何这首歌曲已经存在歌单则不添加
                        withContext(Dispatchers.Main) {
                            Toast.makeText(
                                this@MoBaseActivity,
                                getString(R.string.song_exists_playlist_hint),
                                Toast.LENGTH_LONG
                            ).show()
                        }
                    } else {
                        val isOffline =
                            App.appOfflineDBManager.getOfflineBeanByID(favoriteBean.videoId) != null
                        val isFavorite =
                            App.appFavoriteDBManager.getFavoriteBeanByID(favoriteBean.videoId) != null
                        App.appPlaylistDBManager.insertOrUpdatePlaylistItem(
                            PlaylistItem(
                                playlistId = playlist[position].id,
                                videoId = favoriteBean.videoId,
                                title = favoriteBean.title,
                                name = favoriteBean.name,
                                thumbnail = favoriteBean.thumbnail,
                                isOffline = isOffline,
                                isFavorite = isFavorite
                            )
                        )
                        withContext(Dispatchers.Main) {
                            bottomAddPlaylistSheetDialog.dismiss()
                            Toast.makeText(
                                this@MoBaseActivity,
                                getString(R.string.added_playlist_success_Hint),
                                Toast.LENGTH_LONG
                            ).show()
                        }
                    }
                }
            }
        })
        rv.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        rv.adapter = adapter
    }

    private var bottomSheetDialog: BottomSheetDialog? = null
    private fun showNewPlaylistBottomDialog(favoriteBean: FavoriteBean) {
        bottomSheetDialog = BottomSheetDialog(this)
        val view = layoutInflater.inflate(R.layout.new_playlist_layout, null)
        bottomSheetDialog?.setContentView(view)
        val edit = view.findViewById<EditText>(R.id.playlistEt)
        val confirmBtn = view.findViewById<TextView>(R.id.confirmBtn)
        confirmBtn.setOnClickListener {
            val text = edit.text.toString().trim()
            if (text.isNotEmpty()) {
                launch {
                    val playlist = App.appPlaylistDBManager.getPlaylistByTitle(text)
                    if (playlist != null) {
                        withContext(Dispatchers.Main) {
                            Toast.makeText(
                                this@MoBaseActivity,
                                getString(R.string.new_playlist_duplicate_name_hint),
                                Toast.LENGTH_LONG
                            ).show()
                        }
                    } else {
                        val newPlaylist = Playlist(title = text)
                        App.appPlaylistDBManager.insertOrUpdatePlaylist(newPlaylist)
                        withContext(Dispatchers.Main) {
                            if (bottomSheetDialog != null) {
                                bottomSheetDialog?.dismiss()
                            }
                            Toast.makeText(
                                this@MoBaseActivity,
                                getString(R.string.created_successfully),
                                Toast.LENGTH_LONG
                            ).show()
                        }
                        val currentPlaylist = App.appPlaylistDBManager.getPlaylistByTitle(text)
                        if (currentPlaylist != null) {
                            val isOffline =
                                App.appOfflineDBManager.getOfflineBeanByID(favoriteBean.videoId) != null//返回非null则为true
                            val isFavorite =
                                App.appFavoriteDBManager.getFavoriteBeanByID(favoriteBean.videoId) != null
                            val playlistItem = PlaylistItem(
                                playlistId = currentPlaylist.id,
                                videoId = favoriteBean.videoId,
                                title = favoriteBean.title,
                                name = favoriteBean.name,
                                thumbnail = favoriteBean.thumbnail,
                                isOffline = isOffline,
                                isFavorite = isFavorite
                            )
                            App.appPlaylistDBManager.insertOrUpdatePlaylistItem(playlistItem)
                        }
                    }
                }
            }
        }
        // 设置对话框背景为透明以显示圆角
        bottomSheetDialog?.window?.setBackgroundDrawableResource(android.R.color.transparent)
        bottomSheetDialog?.window?.navigationBarColor =
            ContextCompat.getColor(this, R.color.main_bg_color)
        bottomSheetDialog?.show()
    }

    fun showRatingDialog() {
        val intervalTime = 1000 * 60 * 60 * 24 * 3
        val dialog = RatingDialog(this)
        val installTime = appStore.showRateDialogTime
        val currentTime = System.currentTimeMillis()
        // 检测是否超过间隔时间
        if (currentTime - installTime > intervalTime) {
            dialog.show()
            //更新为当前时间
            appStore.showRateDialogTime = System.currentTimeMillis()
        }
    }
}