package com.gh.gamecenter.download

import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.setPadding
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.IExposable
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.PackageChangeHelper
import com.gh.common.util.PackageInstaller
import com.gh.common.util.PackageLauncher
import com.gh.download.DownloadManager
import com.gh.download.dialog.DownloadDialog
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.databinding.LayoutPopupContainerBinding
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.BugFixedPopupWindow
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.databinding.ItemUpdatableGameBinding
import com.gh.gamecenter.databinding.ItemUpdatableGameHeaderBinding
import com.gh.gamecenter.databinding.ItemUpdatableOtherGameHintBinding
import com.gh.gamecenter.databinding.LayoutPopupOptionItemBinding
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.eventbus.EBSkip
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.home.BlankDividerViewHolder
import com.gh.gamecenter.manager.PackagesManager
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import org.greenrobot.eventbus.EventBus

class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
    RecyclerView.Adapter<RecyclerView.ViewHolder>(), IExposable {

    private var mItemList: ArrayList<UpdatableGameViewModel.UpdatableDataItem>? = null
    private val mExposureSource by lazy {
        ArrayList<ExposureSource>().apply {
            add(ExposureSource("下载管理"))
            add(ExposureSource("游戏更新"))
        }
    }

    val positionAndPackageMap = HashMap<String, Int>()

    fun submitList(dataList: ArrayList<UpdatableGameViewModel.UpdatableDataItem>) {
        positionAndPackageMap.clear()
        // 记录游戏位置
        if (dataList.isNotEmpty()) {
            for (i in 0 until dataList.size) {
                val entity = dataList[i].normalUpdate
                    ?: dataList[i].normalUpdateWithArrow
                    ?: dataList[i].otherVersionUpdate
                    ?: dataList[i].ignoredUpdate
                if (entity != null) {
                    val packages = entity.id + entity.packageName
                    positionAndPackageMap[packages + i] = i
                }
            }
        }
        mItemList = dataList
        notifyDataSetChanged()
    }

    override fun getItemViewType(position: Int): Int {
        val item = mItemList!![position]
        return when {
            item.header != null || item.ignoredUpdateHeader != null || item.landPageAddressDialogHeader != null -> TYPE_HEADER
            item.normalUpdate != null || item.ignoredUpdate != null -> TYPE_NORMAL_GAME
            item.normalUpdateWithArrow != null -> TYPE_NORMAL_GAME_WITH_ARROW
            item.otherVersionUpdateHint != null -> TYPE_OTHER_VERSION_GAME_HINT
            item.otherVersionUpdate != null -> TYPE_OTHER_VERSION_GAME
            item.divider != null -> TYPE_DIVIDER
            else -> TYPE_OTHER_VERSION_GAME
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            TYPE_HEADER -> UpdatableHeaderViewHolder(parent.toBinding())
            TYPE_NORMAL_GAME -> UpdatableGameViewHolder(parent.toBinding())
            TYPE_NORMAL_GAME_WITH_ARROW -> UpdatableGameViewHolder(parent.toBinding())
            TYPE_OTHER_VERSION_GAME -> UpdatableGameViewHolder(parent.toBinding())
            TYPE_OTHER_VERSION_GAME_HINT -> UpdatableOtherVersionGameHintViewHolder(parent.toBinding())
            TYPE_DIVIDER -> BlankDividerViewHolder(parent.toBinding()).also {
                it.binding.container.layoutParams =
                    it.binding.container.layoutParams.apply {
                        height = 8F.dip2px()
                    }
            }

            else -> BlankDividerViewHolder(parent.toBinding())
        }
    }

    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val itemData = mItemList?.get(position)!!
        when (holder) {
            is UpdatableHeaderViewHolder -> {
                val mContext = holder.binding.root.context
                itemData.let {
                    holder.binding.updateAllBtn.enlargeTouchArea()
                    holder.binding.updateAllBtn.goneIf(!itemData.miscShowUpdateAll)
                    holder.binding.updateAllBtn.text = itemData.miscUpdateText
                    holder.binding.updateAllBtn.setOnClickListener {
                        if (itemData.miscUpdateText == "全部更新") {
                            if (mViewModel.hasLandPageAddressDialog()) {
                                DialogHelper.showDialog(
                                    it.context,
                                    title = it.context.getString(R.string.update_all_has_land_page_address_dialog_title),
                                    content = it.context.getString(R.string.update_all_has_land_page_address_dialog_content),
                                    confirmText = it.context.getString(R.string.update_all_has_land_page_address_dialog_confirm),
                                    cancelText = ""
                                )
                            }
                            mViewModel.updateAllMatchedVersionValidUpdate()
                        }
                    }
                    holder.binding.infoTv.text =
                        itemData.header ?: itemData.ignoredUpdateHeader ?: itemData.landPageAddressDialogHeader
                    if (itemData.header != null) {
                        holder.binding.infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
                        (holder.binding.infoTv.layoutParams as ConstraintLayout.LayoutParams).apply {
                            bottomToBottom = ConstraintLayout.LayoutParams.UNSET
                        }
                        holder.binding.root.setOnClickListener(null)
                        holder.binding.root.setPadding(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 0)
                        holder.binding.infoTv.removeDrawable()
                    } else if (itemData.landPageAddressDialogHeader != null) {
                        holder.binding.infoTv.setTextColor(com.gh.gamecenter.common.R.color.secondary_yellow.toColor(mContext))
                        (holder.binding.infoTv.layoutParams as ConstraintLayout.LayoutParams).apply {
                            bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID
                        }
                        holder.binding.root.setOnClickListener(null)
                        holder.binding.root.setPadding(16F.dip2px(), 0, 16F.dip2px(), 0)
                        holder.binding.root.setBackgroundColor(com.gh.gamecenter.common.R.color.home_realname_error.toColor(mContext))
                    } else {
                        holder.binding.infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(mContext))
                        (holder.binding.infoTv.layoutParams as ConstraintLayout.LayoutParams).apply {
                            bottomToBottom = ConstraintLayout.LayoutParams.UNSET
                        }
                        holder.binding.root.setOnClickListener {
                            mViewModel.toggleIgnoredUpdateVisibility()
                        }
                        holder.binding.root.setPadding(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 0)
                        holder.binding.infoTv.setDrawableEnd(
                            if (mViewModel.isIgnoredUpdateExpanded()) {
                                R.drawable.ic_arrow_up_grey.toDrawable()
                            } else {
                                R.drawable.ic_arrow_down_grey.toDrawable()
                            }
                        )
                    }
                }
            }

            is BlankDividerViewHolder -> {
                if (itemData.divider == UpdatableGameViewModel.GREY) {
                    holder.binding.container.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(holder.binding.root.context))
                } else if (itemData.divider == UpdatableGameViewModel.BLUE) {
                    holder.binding.container.setBackgroundColor(com.gh.gamecenter.common.R.color.update_other_version_highlight.toColor(holder.binding.root.context))
                } else {
                    holder.binding.container.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(holder.binding.root.context))
                }
            }

            is UpdatableGameViewHolder -> {
                val update: GameUpdateEntity = (itemData.normalUpdate
                    ?: itemData.normalUpdateWithArrow
                    ?: itemData.otherVersionUpdate
                    ?: itemData.ignoredUpdate)!!

                val context = holder.binding.root.context
                val pluginDesc: String = update.pluginDesc.take(3)
                val downloadManager = DownloadManager.getInstance()

                holder.binding.run {
                    nameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
                    currentVersionTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
                    newVersionTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
                    otherVersionHintIv.goneIf(itemData.normalUpdateWithArrow == null)

                    container.setOnClickListener {
                        DirectUtils.directToGameDetail(
                            context = context,
                            id = update.id,
                            name = update.name ?: "",
                            entrance = mViewModel.entrance,
                            traceEvent = update.exposureEvent
                        )
                    }

                    if (itemData.otherVersionUpdate != null) {
                        container.setBackgroundColor(com.gh.gamecenter.common.R.color.update_other_version_highlight.toColor(context))
                    } else {
                        container.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(context))
                    }

                    iconIv.displayGameIcon(update.rawIcon ?: update.icon, update.iconSubscript, update.iconFloat)
                    val nameText = if (!update.readablePlatform.isNullOrEmpty()) {
                        update.name + " - " + update.readablePlatform
                    } else {
                        update.name
                    }
                    nameTv.text = nameText
                    currentVersionTv.text = "当前：V${update.currentVersion}"
                    newVersionTv.text = "最新：V${update.version} | ${update.size}"
                    optionIv.goneIf(itemData.otherVersionUpdate != null)
                    optionIv.setOnClickListener {
                        showIgnoreOption(it, update, itemData.ignoredUpdate != null)
                    }

                    val downloadEntity = downloadManager.getDownloadEntityByUrl(update.url)
                    updateUpdateBtn(updateBtn, downloadEntity, update, pluginDesc, downloadManager)
                }

                generateExposureEvent(update)
            }

            is UpdatableOtherVersionGameHintViewHolder -> {
                holder.binding.root.setOnClickListener {
                    mViewModel.toggleOtherVersionVisibility(itemData.miscPackageName)
                }
                if (itemData.otherVersionUpdateHint == true) {
                    holder.binding.selectorTv.setDrawableEnd(R.drawable.ic_arrow_up_blue)
                } else {
                    holder.binding.selectorTv.setDrawableEnd(R.drawable.ic_arrow_down_blue)
                }
                holder.binding.closeHintTv.enlargeTouchArea()
                holder.binding.closeHintTv.setOnClickListener {
                    DialogHelper.showDialog(
                        it.context,
                        title = "关闭提示",
                        content = "关闭提示后，将不再提示游戏其他版本的更新",
                        cancelText = "永不更新",
                        confirmText = "仅此次",
                        cancelClickCallback = {
                            mViewModel.suppressUpdate(
                                packageName = itemData.miscPackageName,
                                currentUpdatableVersion = itemData.miscVersion,
                                true
                            )
                        },
                        confirmClickCallback = {
                            mViewModel.suppressUpdate(
                                packageName = itemData.miscPackageName,
                                currentUpdatableVersion = itemData.miscVersion,
                                false
                            )
                        },
                        extraConfig = DialogHelper.Config(showCloseIcon = true)
                    )
                }
            }
        }
    }

    override fun getItemCount() = mItemList?.size ?: 0

    override fun getEventByPosition(pos: Int): ExposureEvent? {
        return mItemList?.get(pos)?.normalUpdate?.exposureEvent
            ?: mItemList?.get(pos)?.normalUpdateWithArrow?.exposureEvent
            ?: mItemList?.get(pos)?.otherVersionUpdate?.exposureEvent
            ?: mItemList?.get(pos)?.ignoredUpdate?.exposureEvent
    }

    override fun getEventListByPosition(pos: Int): List<ExposureEvent>? = null

    private fun showIgnoreOption(view: View, update: GameUpdateEntity, isUpdateIgnored: Boolean) {
        val inflater = LayoutInflater.from(view.context)
        val mainBinding = LayoutPopupContainerBinding.inflate(inflater)
        val popupWindow = BugFixedPopupWindow(
            mainBinding.root,
            LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT
        )

        LayoutPopupOptionItemBinding.inflate(inflater, mainBinding.container, false).apply {
            root.layoutParams = root.layoutParams.apply {
                width = 92F.dip2px()
                height = 44F.dip2px()
            }
            hintText.setPadding(0)
            if (isUpdateIgnored) {
                hintText.text = "取消忽略"
            } else {
                hintText.text = "忽略更新"
            }

            root.setOnClickListener {
                if (isUpdateIgnored) {
                    mViewModel.undoIgnoredUpdate(update.packageName, update.version ?: "")
                } else {
                    mViewModel.ignoreUpdate(update.packageName, update.version ?: "")
                }
                popupWindow.dismiss()
            }
            mainBinding.container.addView(root)
        }

        popupWindow.isTouchable = true
        popupWindow.isFocusable = true

        popupWindow.showAutoOrientation(view)
    }

    private fun updateUpdateBtn(
        updateBtn: DownloadButton,
        downloadEntity: DownloadEntity?,
        update: GameUpdateEntity,
        pluginDesc: String,
        downloadManager: DownloadManager
    ) {
        if (downloadEntity == null) {
            if (PackagesManager.isCanUpdate(update.id, update.packageName, false)) {
                updateBtn.setText(com.gh.gamecenter.feature.R.string.update)
                updateBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
            } else if (update.isPluggable) {
                updateBtn.text = "${pluginDesc}化"
                val samePackageNameDownloadEntity =
                    downloadManager.getDownloadEntityByPackageName(update.packageName)
                if (samePackageNameDownloadEntity == null || samePackageNameDownloadEntity.url == update.url) {
                    updateBtn.isClickable = true
                    updateBtn.buttonStyle = DownloadButton.ButtonStyle.PLUGIN
                } else {
                    updateBtn.isClickable = false
                    updateBtn.buttonStyle = DownloadButton.ButtonStyle.PLUGIN
                    updateBtn.setBackgroundResource(R.drawable.game_item_btn_pause_up)
                }
            } else {
                updateBtn.setText(com.gh.gamecenter.feature.R.string.launch)
                updateBtn.buttonStyle = DownloadButton.ButtonStyle.LAUNCH_OR_OPEN
            }
        } else {
            when (downloadEntity.status) {
                DownloadStatus.downloading -> {
                    updateBtn.text = "${downloadEntity.percent}%"
                    updateBtn.buttonStyle =
                        if (update.isPluggable) DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN else DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
                    updateBtn.progress = (downloadEntity.percent * 10).toInt()
                }

                DownloadStatus.waiting -> {
                    updateBtn.setText(com.gh.gamecenter.feature.R.string.waiting)
                    updateBtn.buttonStyle = DownloadButton.ButtonStyle.WAITING
                }

                DownloadStatus.timeout,
                DownloadStatus.neterror,
                DownloadStatus.subscribe,
                DownloadStatus.overflow,
                DownloadStatus.pause -> {
                    updateBtn.setText(com.gh.gamecenter.feature.R.string.resume)
                    updateBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
                }

                DownloadStatus.done -> {
                    val downloadIsVersionMatched = downloadEntity.versionName == update.version

                    if (downloadIsVersionMatched) {
                        updateBtn.setText(com.gh.gamecenter.feature.R.string.install)
                        updateBtn.buttonStyle =
                            if (update.isPluggable) {
                                DownloadButton.ButtonStyle.INSTALL_PLUGIN
                            } else {
                                DownloadButton.ButtonStyle.INSTALL_NORMAL
                            }
                    } else {
                        updateBtn.setText(com.gh.gamecenter.feature.R.string.update)
                        updateBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
                    }
                }

                else -> {
                    // do nothing
                }
            }
        }

        updateBtn.putWidgetBusinessName("下载管理")
        updateBtn.putObject(update)
        updateBtn.setOnClickListener {
            val str: String = updateBtn.text
            if ("更新" == str || str.contains("化")) {
                // 这里用 CurrentActivity 不用 view.context 的原因是
                // view.context 在 5.0 以下设备会使用 TintContextWrapper 包一层导致类型转换异常
                if ("更新" == str && update.isLandPageAddressDialog()) {// 第三方落地页跳转直接展示跳转弹窗
                    DialogUtils.showLandPageAddressDialog(it.context, update.transformGameEntity()) {// 跳转第三方落地页
                        if (update.isLandPageAddressDialogShowOnly()) {
                            updateOrPluggable(updateBtn, update, downloadEntity, pluginDesc)
                        } else {
                            val packageName = update.packageName
                            if (packageName.isNotEmpty() == true) {
                                PackageChangeHelper.addInstallPendingPackage(packageName)
                            }
                            DirectUtils.directToExternalBrowser(it.context, update.landPageAddressDialog!!.link!!)
                        }
                    }
                    return@setOnClickListener
                }
                updateOrPluggable(updateBtn, update, downloadEntity, pluginDesc)
            } else if (updateBtn.context.getString(com.gh.gamecenter.feature.R.string.launch) == str) {
                PackageLauncher.launchApp(updateBtn.context, packageName = update.packageName)
            } else if (updateBtn.context.getString(com.gh.gamecenter.feature.R.string.resume) == str) {
                if (downloadEntity != null) {
                    DownloadManager.getInstance().resume(downloadEntity, false)
                    updateBtn.text = "${downloadEntity.percent}%"
                    updateBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
                    updateBtn.progress = (downloadEntity.percent * 10).toInt()
                }
            } else if (updateBtn.context.getString(com.gh.gamecenter.feature.R.string.install) == str) {
                val download = DownloadManager.getInstance()
                    .getDownloadEntityByUrl(update.url)
                NewFlatLogUtils.logGameInstall(
                    download?.gameId ?: "",
                    download?.name ?: "",
                    "主动安装"
                )
                SensorsBridge.trackInstallGameClick(
                    download?.gameId ?: "",
                    download?.name ?: "",
                    "主动安装"
                )
                PackageInstaller.install(
                    updateBtn.context,
                    downloadEntity
                )
            } else {
                if (downloadEntity != null) {
                    DownloadManager.getInstance().pause(downloadEntity.url)
                    updateBtn.setText(com.gh.gamecenter.feature.R.string.resume)
                    updateBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
                }
            }
        }
    }

    private fun updateOrPluggable(
        updateBtn: DownloadButton,
        update: GameUpdateEntity,
        downloadEntity: DownloadEntity?,
        pluginDesc: String
    ) {
        val str: String = updateBtn.text
        (CurrentActivityHolder.getCurrentActivity() as? FragmentActivity)?.checkStoragePermissionBeforeAction(
            gameId = update.id,
            gameName = update.name ?: "",
            gameType = update.categoryChinese,
            gameFormat = update.format,
        ) {
            DialogUtils.checkDownload(
                updateBtn.context,
                update.size,
                update.id,
                update.name ?: "",
                update.categoryChinese
            ) { isSubscribe: Boolean ->
                if (str.contains("化")) {
                    if (update.pluggableCollection != null) {
                        DownloadDialog.showDownloadDialog(
                            updateBtn.context,
                            update.transformGameEntity(),
                            update.exposureEvent,
                            mViewModel.entrance,
                            pluginDesc + "化：" + update.name
                        )
                        return@checkDownload
                    } else {
                        updateBtn.text = "0%"
                        updateBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN
                        updateBtn.progress = 0
                    }
                } else {
                    updateBtn.text = "0%"
                    updateBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
                    updateBtn.progress = 0
                }

                // 如果历史下载 downloadEntity 不为空，且版本与当前需要更新的不一致，先移除旧任务再执行更新
                if ((downloadEntity?.isVGameDownloadInDualDownloadMode() == true
                            || downloadEntity?.isLocalDownloadInDualDownloadMode() == true)
                    && (update.version != downloadEntity.versionName)
                ) {
                    DownloadManager.getInstance().cancel(downloadEntity.url ?: "")
                }

                mViewModel.update(update, isSubscribe)
                mViewModel.refreshList()
                EventBus.getDefault()
                    .post(
                        EBSkip(
                            DownloadManagerActivity.TAG,
                            DownloadManagerActivity.INDEX_DOWNLOAD
                        )
                    )
            }
        }
    }

    private fun generateExposureEvent(updateEntity: GameUpdateEntity) {
        updateEntity.exposureEvent =
            createEvent(updateEntity.transformGameEntity(), mExposureSource)
    }

    fun notifyItemByDownload(download: DownloadEntity) {
        for (key in positionAndPackageMap.keys) {
            if (key.contains(download.packageName) && key.contains(download.gameId)) {
                val position = positionAndPackageMap[key]
                if (position != null && mItemList != null && position < (mItemList?.size ?: 0)) {
                    notifyItemChanged(position)
                }
            }
        }
    }

    companion object {
        const val TYPE_DIVIDER = 233
        const val TYPE_HEADER = 234
        const val TYPE_NORMAL_GAME = 235
        const val TYPE_NORMAL_GAME_WITH_ARROW = 236
        const val TYPE_OTHER_VERSION_GAME = 237
        const val TYPE_OTHER_VERSION_GAME_HINT = 238
    }

    class UpdatableHeaderViewHolder(val binding: ItemUpdatableGameHeaderBinding) :
        RecyclerView.ViewHolder(binding.root)

    class UpdatableGameViewHolder(val binding: ItemUpdatableGameBinding) :
        RecyclerView.ViewHolder(binding.root)

    class UpdatableOtherVersionGameHintViewHolder(val binding: ItemUpdatableOtherGameHintBinding) :
        RecyclerView.ViewHolder(binding.root)

}