package com.gh.gamecenter.gamedetail

import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Typeface
import android.os.Build
import android.os.Bundle
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.doOnNextLayout
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import com.ethanhua.skeleton.Skeleton
import com.ethanhua.skeleton.ViewSkeletonScreen
import com.gh.common.constant.Config
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.history.HistoryHelper
import com.gh.common.repository.ReservationRepository
import com.gh.common.simulator.SimulatorGameManager
import com.gh.common.util.*
import com.gh.common.util.LogUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.NewLogUtils
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.DownloadManagerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.ShellActivity
import com.gh.gamecenter.adapter.viewholder.DetailViewHolder
import com.gh.gamecenter.common.base.GlobalActivityManager.getCurrentPageEntity
import com.gh.gamecenter.common.base.GlobalActivityManager.getLastPageEntity
import com.gh.gamecenter.common.base.adapter.FragmentAdapter
import com.gh.gamecenter.common.base.fragment.BaseLazyFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.mvvm.Status
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.WrapContentDraweeView
import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.utils.PageSwitchDataHelper
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.FragmentGameDetailWrapperBinding
import com.gh.gamecenter.databinding.GameDetailTabItemBinding
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.entity.RecommendPopupEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
import com.gh.gamecenter.feature.entity.SimpleGame
import com.gh.gamecenter.feature.eventbus.EBConcernChanged
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper
import com.gh.gamecenter.gamedetail.cloudarchive.CloudArchiveFragment
import com.gh.gamecenter.gamedetail.detail.GameDetailFragment
import com.gh.gamecenter.gamedetail.dialog.GameDetailMoreDialog
import com.gh.gamecenter.gamedetail.dialog.SpecialDownloadDialogFragment
import com.gh.gamecenter.gamedetail.dialog.SpecialDownloadVisibilityViewModel
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity
import com.gh.gamecenter.gamedetail.entity.GameDetailSetting
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
import com.gh.gamecenter.gamedetail.fuli.FuLiFragment
import com.gh.gamecenter.gamedetail.libao.LibaoListFragment
import com.gh.gamecenter.gamedetail.rating.RatingFragment
import com.gh.gamecenter.home.custom.CustomPageFragment
import com.gh.gamecenter.livedata.EventObserver
import com.gh.gamecenter.login.user.UserViewModel
import com.gh.gamecenter.packagehelper.PackageViewModel
import com.gh.gamecenter.simulatorgame.SimulatorGameActivity
import com.gh.vspace.VHelper
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.halo.assistant.HaloApp
import com.halo.assistant.fragment.WebFragment
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.lightgame.download.DownloadStatus
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import retrofit2.HttpException
import splitties.views.horizontalPadding
import java.util.*

class GameDetailWrapperFragment : BaseLazyFragment(), IScrollable {
    private val binding by lazy { FragmentGameDetailWrapperBinding.inflate(layoutInflater) }
    private val bodyBinding by lazy { binding.bodyContainer }
    private val downloadBinding by lazy { binding.detailLlBottom }
    private val recommendBinding by lazy { binding.gameDetailRecommendView }
    private lateinit var viewModel: GameDetailViewModel
    private val packageViewModel: PackageViewModel by lazy { viewModelProvider(PackageViewModel.Factory()) }
    private val userViewModel: UserViewModel by lazy { viewModelProvider(UserViewModel.Factory(HaloApp.getInstance().application)) }
    private val acceleratorUiHelper: GameDetailAcceleratorUiHelper by lazy { GameDetailAcceleratorUiHelper(binding.detailLlBottom) }

    private var moreMenuItem: MenuItem? = null
    private var downloadMenuItem: MenuItem? = null
    private var downloadMenuIcon: ImageView? = null
    private var downloadCountHint: TextView? = null

    private var gameEntity: GameEntity? = null
    private var gameDetailSetting: GameDetailSetting? = null

    private var isRecommendViewShow = false
    private var recommendDisposable: Disposable? = null
    private var recommendPopupEntity: RecommendPopupEntity? = null

    private var autoDownload: Boolean = false
    private var traceEvent: ExposureEvent? = null
    private var skipGameComment: Boolean = false
    private var isOpenPlatformWindow: Boolean = false
    private var destinationTab = -1 // 供快捷跳转到某个 tab 使用
    private var showConcernOnMenu = false

    private val tabBindingList = arrayListOf<GameDetailTabItemBinding>()
    private val tabEntityList = ArrayList<GameDetailTabEntity>()
    private val fragmentsList = ArrayList<Fragment>()
    private var tabClickEvent: Pair<Long, String> = Pair(0L, "")

    private var skeleton: ViewSkeletonScreen? = null
    private var currentVpPosition: Int = 0

    private val dataWatcher = object : DataWatcher() {
        override fun onDataChanged(downloadEntity: DownloadEntity) {
            if (downloadEntity.gameId == viewModel.gameId) {
                if (downloadEntity.status == DownloadStatus.add
                    || downloadEntity.status == DownloadStatus.done
                    || downloadEntity.status == DownloadStatus.downloading
                    || downloadEntity.status == DownloadStatus.pause
                    || downloadEntity.status == DownloadStatus.redirected
                ) {
                    // 特殊下载弹窗
                    if (isSpecialDownloadDialogAvailable(downloadEntity) && !isSpecialDownloadDetailFragmentIsShowing()) {
                        updateSpecialDownloadDialogIcon(true)

                        if (downloadEntity.status == DownloadStatus.add) {
                            showSpecialDownloadDialog()
                        }
                    }

                    showInstallHint()
                    if (!SPUtils.getBoolean(Constants.SP_SHOULD_SHOW_GAME_DETAIL_INSTALL_GUIDE, false)) {
                        SPUtils.setBoolean(Constants.SP_SHOULD_SHOW_GAME_DETAIL_INSTALL_GUIDE, true)
                    }
                }

                if (downloadEntity.status == DownloadStatus.cancel) {
                    updateSpecialDownloadDialogIcon(false)
                }

                if (gameEntity?.getApk()?.size == 1) {
                    DetailDownloadUtils.updateViewHolder(detailViewHolder)

                    if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) {
                        DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
                    }

                    val gameDetailRecommendMeta =
                        downloadEntity.getMetaExtra(PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND)
                    if (downloadEntity.status == DownloadStatus.add) {
                        recommendBinding.recommendView.postDelayed({ showRecommendView() }, 500)
                        if (gameDetailRecommendMeta.isNotEmpty() && recommendPopupEntity != null) {
                            LogUtils.uploadRecommendPopup(
                                "recommend_pop_download",
                                recommendPopupEntity?.id,
                                viewModel.game?.id ?: "",
                                viewModel.game?.name ?: "",
                                recommendPopupEntity?.popupDetail?.link?.type,
                                recommendPopupEntity?.popupDetail?.link?.text,
                                downloadEntity.gameId,
                                downloadEntity.name
                            )
                        }
                    } else if (downloadEntity.status == DownloadStatus.done) {
                        hideRecommendView()
                        if (gameDetailRecommendMeta.isNotEmpty() && recommendPopupEntity != null) {
                            LogUtils.uploadRecommendPopup(
                                "recommend_pop_download_complete",
                                recommendPopupEntity?.id,
                                viewModel.game?.id ?: "",
                                viewModel.game?.name ?: "",
                                recommendPopupEntity?.popupDetail?.link?.type,
                                recommendPopupEntity?.popupDetail?.link?.text,
                                downloadEntity.gameId,
                                downloadEntity.name
                            )
                        }
                    }
                } else if ((gameEntity?.getApk()?.size ?: 0) > 1) {
                    when (downloadEntity.status) {
                        DownloadStatus.downloading -> {
                            if (detailViewHolder.downloadTips.visibility == View.GONE || !detailViewHolder.downloadTips.isAnimating) {
                                detailViewHolder.downloadTips.visibility = View.VISIBLE
                                detailViewHolder.downloadTips.setDownloadTipsAnimation(true)
                            }
                        }

                        DownloadStatus.done,
                        DownloadStatus.pause,
                        DownloadStatus.waiting,
                        DownloadStatus.timeout,
                        DownloadStatus.subscribe,
                        DownloadStatus.overflow,
                        DownloadStatus.neterror -> {
                            detailViewHolder.downloadTips.visibility = View.VISIBLE
                            detailViewHolder.downloadTips.setDownloadTipsAnimation(false)
                        }

                        else -> detailViewHolder.downloadTips.visibility = View.GONE
                    }
                }
            }
        }

        override fun onDataInit(downloadEntity: DownloadEntity) {
            onDataChanged(downloadEntity)
        }
    }

    fun provideDownloadButton() = downloadBinding.detailProgressbar

    // 下载按钮ViewHolder
    // 每次获取需要重新创建, 防止数据刷新
    private val detailViewHolder: DetailViewHolder
        get() =
            DetailViewHolder(
                view = mCachedView,
                viewModel = viewModel,
                gameEntity = gameEntity!!,
                isNewsDetail = false,
                entrance = mEntrance,
                name = "游戏详情",
                title = gameEntity!!.name ?: "",
                traceEvent = traceEvent,
                acceleratorUiHelper = acceleratorUiHelper,
                isSupportDualButton = true
            ) {
                viewModel.isDownloadClick = true
                viewModel.scrollToSpecificPositionOnDownloadClick(it)
            }


    override fun getLayoutId(): Int = 0
    override fun getInflatedLayout(): View = binding.root

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        for (fragment in childFragmentManager.fragments) {
            fragment.onActivityResult(requestCode, resultCode, data)
        }
    }

    override fun onSaveInstanceState(outState: Bundle) {
        bodyBinding.viewPager.let { outState.putInt(LAST_SELECTED_POSITION, it.currentItem) }
        super.onSaveInstanceState(outState)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        savedInstanceState?.let { destinationTab = it.getInt(LAST_SELECTED_POSITION) }

        val args = arguments ?: Bundle()
        autoDownload = args.getBoolean(EntranceConsts.KEY_AUTO_DOWNLOAD)
        traceEvent = args.getParcelable(EntranceConsts.KEY_TRACE_EVENT)
        skipGameComment = args.getBoolean(EntranceConsts.KEY_COMMENT_AS_DEFAULT_TAB)
        isOpenPlatformWindow = args.getBoolean(EntranceConsts.KEY_OPEN_PLATFORM_WINDOW)
    }

    override fun onFragmentFirstVisible() {
        super.onFragmentFirstVisible()
        initSkeleton()

        binding.reuseNoneData.reuseNoneDataTv.text = "页面不见了"
        bodyBinding.tabIndicator.setIndicatorWidth(16)
        bodyBinding.viewPager.offscreenPageLimit = 4
        binding.expandSpecialDownloadIv.enlargeTouchArea()

        val gameId = arguments?.getString(EntranceConsts.KEY_GAME_ID) ?: ""
        val factory = GameDetailViewModel.Factory(
            HaloApp.getInstance().application,
            gameId,
            arguments?.getParcelable(EntranceConsts.KEY_GAME_ENTITY)
        )
        viewModel = viewModelProviderFromParent(factory, gameId)

        initMenu()
        observeData()
        setListener()
        updateDivider()
    }

    override fun onFragmentResume() {
        super.onFragmentResume()
        viewModel.isSkipOnPageSelected = false
        if (gameEntity != null && (gameEntity!!.getApk().size == 1 || gameEntity!!.isReservable)) {
            DetailDownloadUtils.updateViewHolder(detailViewHolder)
        }
        showBrowserInstallHintIfNeeded()

        DownloadManager.getInstance().addObserver(dataWatcher)
        controlInstallHint()

        viewModel.refreshWrongInstallStatus()
    }

    override fun onFragmentPause() {
        super.onFragmentPause()
        hideRecommendView()
    }

    override fun onParentActivityFinish() {
        NewFlatLogUtils.logGameDetailExit(gameEntity?.name ?: "", gameEntity?.id ?: "")
    }

    override fun onDestroy() {
        super.onDestroy()
        if (recommendDisposable != null) {
            recommendDisposable!!.dispose()
            recommendDisposable = null
        }
        DownloadManager.getInstance().removeObserver(dataWatcher)

        if (::viewModel.isInitialized) {
            val isFirstTime = HistoryHelper.getHistoryGameDetailById(viewModel.game?.id ?: "") == null
            SensorsBridge.trackEvent("GameDetailPageLeave", json {
                "game_id" to gameEntity?.id
                "game_name" to gameEntity?.name
                "game_type" to gameEntity?.categoryChinese
                "page_depth" to viewModel.pageDepth
                "\$is_first_time" to isFirstTime
                "is_download" to viewModel.isDownloadClick
            })
        }
        acceleratorUiHelper.clear()
    }

    private fun initMenu() {
        bodyBinding.run {
            requireActivity().menuInflater.inflate(R.menu.menu_game_detail, actionMenuView.menu)
            if (mIsFromMainWrapper || mIsFromTabWrapper) {
                backContainer.visibility = View.GONE
            }
            backBtn.setOnClickListener { requireActivity().finish() }
            moreMenuItem = actionMenuView.menu.findItem(R.id.menu_more)
            downloadMenuItem = actionMenuView.menu.findItem(R.id.menu_download)?.apply {
                actionView?.updateLayoutParams<LayoutParams> { width = 40F.dip2px() }
            }
            downloadMenuItem?.isVisible = Config.isShow()
            actionMenuView.findViewById<ActionMenuItemView>(R.id.menu_more)?.run {
                updateLayoutParams<LayoutParams> { width = 40F.dip2px() }
                horizontalPadding = 8F.dip2px()
            }
        }

        downloadMenuIcon = downloadMenuItem?.actionView?.findViewById(R.id.menu_download_iv)
        moreMenuItem?.setOnMenuItemClickListener {
            consume {
                when (it.itemId) {
                    R.id.menu_more -> {
                        if (gameEntity != null) {
                            GameDetailMoreDialog.showMoreDialog(
                                requireActivity() as AppCompatActivity,
                                gameEntity,
                                gameDetailSetting?.shortId ?: "",
                                showConcernOnMenu,
                                viewModel.meLiveData.value?.isGameConcerned ?: false
                            )
                        }
                    }
                }
            }
        }
        downloadMenuItem?.actionView?.setOnClickListener {
            val intent = DownloadManagerActivity.getDownloadMangerIntent(requireContext(), mEntrance)
            startActivity(intent)
        }

        updateDownloadIcon()
    }

    private fun observeData() {
        viewModel.gameLiveData.observeNonNull(viewLifecycleOwner) { gameResource ->
            if (gameResource.status == Status.SUCCESS) {
                viewModel.logHistory(gameResource.data!!)
                gameEntity = gameResource.data
                initAccelerator()
                showBrowserInstallHintIfNeeded()
                controlInstallHint()
                // 添加启动弹窗的相关信息
                if (mEntrance.contains(EntranceConsts.ENTRANCE_WELCOME) && mEntrance.countOccurrences("+") <= 1) {
                    gameEntity?.setWelcomeDialogInfoIfAvailable()
                }
                NewFlatLogUtils.logGameDetailEnter(
                    gameEntity?.name ?: "",
                    gameEntity?.id ?: "",
                    gameEntity?.shouldUseMirrorInfo() ?: false
                )
            } else if (gameResource.status == Status.ERROR) {
                loadErrorControl(gameResource.exception)
            }
        }
        viewModel.gameDetailSettingLiveData.observeNonNull(viewLifecycleOwner) {
            gameDetailSetting = it
            showAlertDialogIfNeeded(it.detailDialogs)
            controlReserveBtn()
            gameEntity?.run { showVModeIconAtBottomBarIfNeeded(it.smoothRelatedGame, this) }
            showConcernIconAtBottomBarIfAvailable()
            // 底部按钮尺寸已确定，可以显示按钮上的引导页
            acceleratorUiHelper.isButtonSizeDetermined = true
            acceleratorUiHelper.showGuideLayerIfNeed()
        }
        viewModel.gameDetailTabListLiveData.observeNonNull(viewLifecycleOwner) {
            if (it.status == Status.SUCCESS) {
                it.data?.let { data ->
                    tabEntityList.clear()
                    tabEntityList.addAll(data)
                    initViewPager()

                    postDelayedRunnable({
                        val buttonName = when {
                            downloadBinding.detailProgressbar.text.isNotBlank() -> downloadBinding.detailProgressbar.text
                            downloadBinding.overlayTv.isVisible && downloadBinding.overlayTv.text.isNotBlank() ->
                                downloadBinding.overlayTv.text.toString()

                            downloadBinding.multiVersionDownloadTv.isVisible && downloadBinding.multiVersionDownloadTv.text.isNotBlank() ->
                                downloadBinding.multiVersionDownloadTv.text.toString()

                            else -> ""
                        }
                        SensorsBridge.trackEventWithExposureSource(
                            "GameDetailPageShow",
                            traceEvent?.source ?: listOf(ExposureSource(mEntrance)),
                            "game_id",
                            gameEntity?.id ?: "",
                            "game_name",
                            gameEntity?.name ?: "",
                            "download_status",
                            gameEntity?.downloadStatusChinese ?: "",
                            "cloud_save_tab_status",
                            if (data.find { tabEntity -> tabEntity.type == GameDetailTabEntity.TYPE_ARCHIVE } != null) "开启" else "关闭",
                            "game_type",
                            gameEntity?.categoryChinese ?: "",
                            "page_name",
                            getCurrentPageEntity().pageName,
                            "page_id",
                            getCurrentPageEntity().pageId,
                            "page_business_id",
                            getCurrentPageEntity().pageBusinessId,
                            "last_page_name",
                            getLastPageEntity().pageName,
                            "last_page_id",
                            getLastPageEntity().pageId,
                            "last_page_business_id",
                            getLastPageEntity().pageBusinessId,
                            "button_name",
                            buttonName,
                            "game_schema_type",
                            gameEntity?.gameBitChinese ?: "",
                            "download_type",
                            gameEntity?.downloadType ?: "",
                            "is_ad",
                            traceEvent?.payload?.isAd ?: false,
                            "ad_group_id",
                            traceEvent?.payload?.adGroupId ?: "",
                            *(traceEvent?.additional ?: emptyArray())
                        )
                    }, 120)

                    val viewHolder = detailViewHolder
                    DetailDownloadUtils.updateViewHolder(viewHolder)
                    binding.divider.isVisible = binding.detailLlBottom.root.isVisible

                    if (autoDownload || isOpenPlatformWindow && gameEntity!!.getApk().size > 1) {
                        viewHolder.downloadPb.performClick()
                        autoDownload = false
                    }

                    val downloadEntitySnapshot = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
                    if (isSpecialDownloadDialogAvailable(downloadEntitySnapshot)
                        && downloadEntitySnapshot != null
                    ) {
                        updateSpecialDownloadDialogIcon(true)
                    }
                    binding.expandSpecialDownloadIv.setOnClickListener {
                        showSpecialDownloadDialog()
                    }
                }
            } else if (it.status == Status.ERROR) {
                loadErrorControl(it.exception)
            }
        }
        viewModel.detailDataListLiveData.observeNonNull(viewLifecycleOwner) {
            skeleton?.hide()
        }

        viewModel.concernLiveData.observeNonNull(viewLifecycleOwner) { response ->
            if (response.isConcern) {
                if (response.isSuccess) {
                    DataCollectionUtils.uploadConcern(
                        context,
                        gameEntity!!.name,
                        gameEntity!!.id,
                        "关注"
                    )
                    toast(com.gh.gamecenter.feature.R.string.concern_success)
                } else {
                    toast(com.gh.gamecenter.feature.R.string.concern_failure)
                }
            } else {
                if (response.isSuccess) {
                    DataCollectionUtils.uploadConcern(
                        context,
                        gameEntity!!.name,
                        gameEntity!!.id,
                        "取消关注"
                    )
                } else {
                    toast(R.string.cancel_concern_failure)
                }
            }
        }

        packageViewModel.filterSameUpdateLiveData.observe(viewLifecycleOwner) {
            updateDownloadCountHint(it)
        }

        viewModel.recommendPopupLiveData.observe(viewLifecycleOwner) {
            initRecommendUI()
        }

        viewModel.archiveStatusLiveData.observeNonNull(viewLifecycleOwner) { hasNew ->
            updateArchiveTabUI(hasNew)
        }

        viewModel.tabSelectedLiveData.observe(viewLifecycleOwner, EventObserver { link ->
            val tabIndex = tabEntityList.indexOfFirst {
                if (!link.type.isNullOrEmpty()) {
                    it.type == link.type
                } else {
                    it.id == link.link
                }
            }
            if (tabIndex != -1) {
                bodyBinding.viewPager.currentItem = tabIndex
            }
        })

        viewModel.meLiveData.observe(viewLifecycleOwner) {
            updateConcernMenuIcon(it.isGameConcerned)
        }

        userViewModel.loginObsUserinfo.observe(viewLifecycleOwner) {
            if (it != null && gameEntity != null) {
                postDelayedRunnable({
                    controlReserveBtn()
                    DetailDownloadUtils.updateViewHolder(detailViewHolder)
                }, 100)
            }
        }
    }

    private fun initAccelerator() {
        gameEntity?.let { game ->
            if (game.canSpeed) {
                acceleratorUiHelper.initUi(game, requireContext())

                viewModel.lastAcctGame.observe(viewLifecycleOwner) {
                    acceleratorUiHelper.setCurrentAcctGameInfo(it)
                }

                viewModel.hasAnyRecord.observe(viewLifecycleOwner) {
                    acceleratorUiHelper.setHasAnyAcctRecord(it)
                }

                viewModel.loadRecordDataInDatabase(game.id)
            }
        }
    }

    private fun updateArchiveTabUI(hasNew: Boolean) {
        if (hasNew) {
            val archivePosition = tabEntityList.indexOfFirst { it.type == GameDetailTabEntity.TYPE_ARCHIVE }
            if (archivePosition != -1) {
                tabBindingList.getOrNull(archivePosition)?.run {
                    if (!newIv.isVisible) {
                        newIv.isVisible = true
                        root.setPadding(8F.dip2px(), 0, 22F.dip2px(), 0)
                    }
                }
            }
        }
    }

    private fun showAlertDialogIfNeeded(dialogs: ArrayList<GameEntity.Dialog>) {
        if (dialogs.isEmpty()) return
        val dialog = retrieveAvailableDialog(dialogs)
        if (dialog != null) {
            val dayOfMonth = Calendar.getInstance().get(Calendar.DAY_OF_MONTH)
            if ("EVERY_TIME_OPEN" == dialog.alert || SPUtils.getLong(
                    SP_OPENED_DIALOG_TIME_PREFIX + gameEntity?.id,
                    0
                ) != dayOfMonth.toLong()
            ) {
                SPUtils.setLong(SP_OPENED_DIALOG_TIME_PREFIX + gameEntity?.id, dayOfMonth.toLong())
                doShowAlertDialog(dialog)
            }
        }
    }

    private fun retrieveAvailableDialog(detailDialogs: ArrayList<GameEntity.Dialog>): GameEntity.Dialog? {
        for (dialog in detailDialogs) {
            val versionName = PackageUtils.getGhVersionName()
            val noticeVersions = dialog.rule.noticeVersions
            if (noticeVersions.isEmpty() || noticeVersions.contains(versionName)) {
                if (dialog.rule.models.isEmpty() || dialog.rule.models.contains(Build.MODEL)) {
                    return dialog
                }
            } else return null
        }
        return null
    }

    private fun doShowAlertDialog(dialog: GameEntity.Dialog) {
        SensorsBridge.trackEvent(
            "GameDetailDialogShow",
            "game_id", gameEntity?.id ?: "",
            "game_name", gameEntity?.name ?: "",
            "game_type", gameEntity?.categoryChinese ?: ""
        )
        DialogHelper.showDialogWithHtmlContent(
            requireContext(),
            dialog.title,
            dialog.content.replaceLineBreakWithBr(),
            dialog.confirmButton.text.toString(),
            dialog.closeButtonText,
            {
                SensorsBridge.trackEvent(
                    "GameDetailDialogClick",
                    "game_id", gameEntity?.id ?: "",
                    "game_name", gameEntity?.name ?: "",
                    "game_type", gameEntity?.categoryChinese ?: "",
                    "link_type", dialog.confirmButton.type ?: "",
                    "link_id", dialog.confirmButton.link ?: "",
                    "link_text", dialog.confirmButton.linkText ?: "",
                    "button_name", dialog.confirmButton.text.toString()
                )
                dialog.confirmButton.text = dialog.confirmButton.linkText
                DirectUtils.directToLinkPage(requireContext(), dialog.confirmButton, mEntrance, "")
            },
            {
                SensorsBridge.trackEvent(
                    "GameDetailDialogClick",
                    "game_id", gameEntity?.id ?: "",
                    "game_name", gameEntity?.name ?: "",
                    "game_type", gameEntity?.categoryChinese ?: "",
                    "button_name", dialog.closeButtonText
                )
            },
            {
                SensorsBridge.trackEvent(
                    "GameDetailDialogClick",
                    "game_id", gameEntity?.id ?: "",
                    "game_name", gameEntity?.name ?: "",
                    "game_type", gameEntity?.categoryChinese ?: "",
                    "button_name", "关闭弹窗"
                )
            },
            extraConfig = DialogHelper.Config(centerTitle = true)
        )
    }

    private fun initViewPager() {
        fragmentsList.clear()
        bodyBinding.run {
            viewPager.visibility = View.VISIBLE

            val targetTabType = arguments?.getString(EntranceConsts.KEY_TARGET, GameDetailTabEntity.TYPE_DETAIL)
                ?: GameDetailTabEntity.TYPE_DETAIL
            val targetTabIndex = tabEntityList.indexOfFirst { tabEntity -> tabEntity.type == targetTabType }
            destinationTab = if (targetTabIndex != -1) targetTabIndex else 0

            val tag = "android:switcher:${viewPager.id}:"
            tabEntityList.forEachIndexed { index, tabEntity ->
                var fragment = childFragmentManager.findFragmentByTag("${tag}${tabEntity.name}")
                val bundle = Bundle()
                bundle.putParcelable(EntranceConsts.KEY_GAME_ENTITY, gameEntity)
                bundle.putString(EntranceConsts.KEY_ENTRANCE, mEntrance)
                when (tabEntity.type) {
                    GameDetailTabEntity.TYPE_DETAIL -> {
                        fragment = fragment ?: GameDetailFragment()
                        bundle.putAll(arguments)
                        if (targetTabIndex == -1) {
                            // 无对应Tab则触发点击对应内容卡片
                            val contentCardType = when (targetTabType) {
                                GameDetailTabEntity.TYPE_GIFT -> ContentCardEntity.TYPE_GIFT
                                GameDetailTabEntity.TYPE_BBS -> ContentCardEntity.TYPE_BBS
                                GameDetailTabEntity.TYPE_ZONE -> ContentCardEntity.TYPE_ZONE
                                else -> null
                            }
                            bundle.putString(EntranceConsts.KEY_PERFORM_CONTENT_CARD_CLICK_TYPE, contentCardType)
                        }
                    }

                    GameDetailTabEntity.TYPE_ARCHIVE -> {
                        fragment = fragment ?: CloudArchiveFragment()
                        bundle.putParcelable(EntranceConsts.KEY_GAME, gameEntity ?: GameEntity())
                        bundle.putString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL, tabEntity.archiveConfigUrl)
                    }

                    GameDetailTabEntity.TYPE_COMMENT -> {
                        fragment = fragment ?: RatingFragment()
                        bundle.putBoolean(EntranceConsts.KEY_COMMENT_AS_DEFAULT_TAB, skipGameComment)
                        bundle.putBoolean(EntranceConsts.KEY_DIRECT_COMMENT, gameEntity?.directComment ?: false)
                    }

                    GameDetailTabEntity.TYPE_BBS -> {
                        fragment = fragment ?: Fragment()
                    }

                    GameDetailTabEntity.TYPE_ZONE -> {
                        val zone = gameEntity?.zone
                        if (zone?.style == "link") {
                            //显示web页面
                            fragment = fragment ?: WebFragment()
                            bundle.putString(EntranceConsts.KEY_ENTRANCE, "游戏专区")
                            bundle.putString(EntranceConsts.KEY_URL, zone.link)
                            bundle.putBoolean(WebFragment.KEY_ENABLE_HORIZONTAL_SCROLL_DISPATCH, true)
                            bundle.putBoolean(WebFragment.KEY_FORCE_ENABLE_NESTED_SCROLL, true)
                        } else {
                            fragment = fragment ?: FuLiFragment()
                        }
                    }

                    GameDetailTabEntity.TYPE_WEB -> {
                        fragment = fragment ?: WebFragment()
                        bundle.putString(EntranceConsts.KEY_URL, tabEntity.link?.link)
                        bundle.putBoolean(WebFragment.KEY_ENABLE_HORIZONTAL_SCROLL_DISPATCH, true)
                        bundle.putBoolean(WebFragment.KEY_FORCE_ENABLE_NESTED_SCROLL, true)
                        bundle.putBoolean(
                            WebFragment.KEY_LEAVE_WEB_PAGE_TO_HANDLE_BACK_PRESSED,
                            tabEntity.link?.link?.contains("leave_web_page_handle_back_pressed=true") == true
                        )
                    }

                    GameDetailTabEntity.TYPE_GIFT -> {
                        fragment = fragment ?: LibaoListFragment()
                        gameEntity?.let {
                            bundle.putAll(LibaoListFragment.getBundle(it, true))
                        }
                    }

                    GameDetailTabEntity.TYPE_CUSTOM_PAGE -> {
                        fragment = fragment ?: CustomPageFragment()
                        bundle.putString(EntranceConsts.KEY_CUSTOM_PAGE_ID, tabEntity.link?.link)
                        bundle.putString(EntranceConsts.KEY_CUSTOM_PAGE_NAME, tabEntity.link?.text)
                        bundle.putBoolean(EntranceConsts.KEY_SHOW_FLOATING_WINDOW, false)
                        bundle.putBoolean(EntranceConsts.KEY_SHOW_PULL_DOWN_PUSH, false)
                    }
                }
                fragment?.let {
                    it.arguments = bundle
                    fragmentsList.add(it)
                }
            }
            viewPager.setRestoredCurItem(destinationTab)
            onPageSelected(destinationTab)
            viewPager.offscreenPageLimit = fragmentsList.size
            viewPager.adapter =
                FragmentAdapter(childFragmentManager, fragmentsList, tabEntityList.map { it.name })
            viewPager.doOnPageSelected { position ->
                logTabClick(position)
                onPageSelected(position)
                hideRecommendView()
            }

            tabLayout.setupWithViewPager(viewPager)
            (tabLayout.getChildAt(0) as? LinearLayout)?.clipChildren = false
            tabIndicator.setupWithTabLayout(tabLayout)
            tabIndicator.setupWithViewPager(viewPager)
            initTabView()
        }
    }

    private fun logTabClick(position: Int) {
        // 特殊处理延时选中 tab 时可能 fragment 已被移除的情况
        if (!isAdded) return

        val tabEntity = tabEntityList.getOrNull(position) ?: return
        SensorsBridge.trackGameDetailPageTabSelect(
            gameId = gameEntity?.id ?: "",
            gameName = gameEntity?.name ?: "",
            pageName = getCurrentPageEntity().pageName,
            pageId = getCurrentPageEntity().pageId,
            pageBusinessId = getCurrentPageEntity().pageBusinessId,
            lastPageName = getLastPageEntity().pageName,
            lastPageId = getLastPageEntity().pageId,
            lastPageBusinessId = getLastPageEntity().pageBusinessId,
            downloadStatus = gameEntity?.downloadStatusChinese ?: "",
            gameType = gameEntity?.categoryChinese ?: "",
            position = position,
            tabContent = tabEntity.name
        )

        val entrance = if (mEntrance.contains("论坛详情")) "论坛" else "游戏"
        gameEntity?.run {
            when (tabEntity.type) {
                GameDetailTabEntity.TYPE_DETAIL -> {
                    NewLogUtils.logGameDetailTabClick(name ?: "", id, "详情")
                }

                GameDetailTabEntity.TYPE_ZONE -> {
                    NewLogUtils.logGameDetailTabClick(
                        "view_game_detail_special_area_tab",
                        entrance,
                        id,
                        gameType,
                        bbsId
                    )
                    NewLogUtils.logGameDetailTabClick(name ?: "", id, "专区")
                }

                GameDetailTabEntity.TYPE_ARCHIVE -> {
                    NewFlatLogUtils.logCloudArchiveGameDetailTabRelated(
                        "cloud_save_tab_click",
                        gameEntity?.id ?: "",
                        gameEntity?.name ?: ""
                    )
                    SensorsBridge.trackEvent(
                        "CloudSaveTabSelected",
                        "game_id", gameEntity?.id ?: "",
                        "game_name", gameEntity?.name ?: "",
                        "page_name", getCurrentPageEntity().pageName,
                        "page_id", getCurrentPageEntity().pageId,
                        "page_business_id", getCurrentPageEntity().pageBusinessId,
                        "last_page_name", getLastPageEntity().pageName,
                        "last_page_id", getLastPageEntity().pageId,
                        "last_page_business_id", getLastPageEntity().pageBusinessId
                    )
                }

                GameDetailTabEntity.TYPE_COMMENT -> {
                    NewLogUtils.logGameDetailTabClick("view_game_detail_comment_tab", entrance, id, gameType, bbsId)
                    NewLogUtils.logGameDetailTabClick(name ?: "", id, "评论")
                }

                GameDetailTabEntity.TYPE_BBS -> {
                    NewLogUtils.logGameDetailTabClick(name ?: "", id, "论坛")
                }
            }
        }
    }

    private fun onPageSelected(position: Int) {
        val tabEntity = tabEntityList.getOrNull(position) ?: return

        when (tabEntity.type) {
            GameDetailTabEntity.TYPE_BBS -> {
                tabEntity.link?.let {
                    viewModel.isSkipOnPageSelected = true
                    DirectUtils.directToLinkPage(
                        requireContext(),
                        it,
                        "游戏详情",
                        ""
                    )
                    LogUtils.uploadAccessToBbs(it.link, "游戏详情")
                    val skipPosition = currentVpPosition
                    bodyBinding.viewPager.doOnNextLayout {
                        bodyBinding.viewPager.currentItem = skipPosition
                    }
                }
            }
        }

        currentVpPosition = position
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun initTabView() {
        tabBindingList.clear()
        for (i in 0 until tabEntityList.size) {
            val tab = bodyBinding.tabLayout.getTabAt(i) ?: continue
            val tabEntity = tabEntityList.getOrNull(i)
            val tabItemBinding = GameDetailTabItemBinding.inflate(layoutInflater).apply {
                tabTitle.text = tabEntity?.name
                if (tabEntity?.type == GameDetailTabEntity.TYPE_ARCHIVE) {
                    val hasEnterArchiveGameDetail =
                        SPUtils.getBoolean(SP_HAS_ENTER_ARCHIVE_GAME_DETAIL_PREFIX + (gameEntity?.id ?: ""))
                    val hasNewArchive = viewModel.archiveStatusLiveData.value ?: false
                    newIv.goneIf(hasEnterArchiveGameDetail && !hasNewArchive) {
                        if (i == tabEntityList.size - 1) {
                            root.setPadding(8F.dip2px(), 0, 22F.dip2px(), 0)
                        }
                    }
                    if (!hasEnterArchiveGameDetail) {
                        SPUtils.setBoolean(SP_HAS_ENTER_ARCHIVE_GAME_DETAIL_PREFIX + (gameEntity?.id ?: ""), true)
                    }
                }
            }
            tabBindingList.add(tabItemBinding)
            tab.customView = tabItemBinding.root
            updateTabStyle(tab, i == bodyBinding.viewPager.currentItem)
            tab.view.clipChildren = false
            tab.view.setPadding(0, 0, if (i == tabEntityList.size - 1) 8F.dip2px() else 0, 0)
            tab.view.setOnTouchListener { _, event ->
                if (event.action == MotionEvent.ACTION_DOWN) {
                    handleTabTouchEvent(tabEntity?.name ?: "")
                }
                return@setOnTouchListener false
            }
        }
        bodyBinding.tabLayout.addOnTabSelectedListener(object : OnTabSelectedListener {
            override fun onTabSelected(tab: TabLayout.Tab) {
                updateTabStyle(tab, true)
            }

            override fun onTabUnselected(tab: TabLayout.Tab) {
                updateTabStyle(tab, false)
            }

            override fun onTabReselected(tab: TabLayout.Tab) {
                updateTabStyle(tab, true)
            }
        })
    }

    private fun updateTabStyle(tab: TabLayout.Tab, isChecked: Boolean) {
        tab.customView?.findViewById<TextView>(R.id.tab_title)
            ?.setTypeface(if (isChecked) Typeface.DEFAULT_BOLD else Typeface.DEFAULT)
        tab.customView?.findViewById<TextView>(R.id.tab_title)?.setTextColor(
            if (isChecked) com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()) else com.gh.gamecenter.common.R.color.text_secondary.toColor(
                requireContext()
            )
        )
    }

    private fun handleTabTouchEvent(title: String) {
        if (title == tabClickEvent.second && System.currentTimeMillis() - tabClickEvent.first < 300) {
            val fragment = fragmentsList[bodyBinding.viewPager.currentItem]
            if (fragment is IScrollable && fragment.isAdded) {
                fragment.scrollToTop()
            }
        } else {
            tabClickEvent = Pair(System.currentTimeMillis(), title)
        }
    }

    private fun setListener() {
        bodyBinding.toolbar.setOnClickListener {
            scrollToTop()
        }
        binding.reuseNoConnection.root.setOnClickListener {
            binding.reuseNoConnection.reuseNoConnection.visibility = View.GONE
            binding.errorToolbarContainer.visibility = View.GONE
            viewModel.loadData()
            skeleton?.show()
        }
        downloadBinding.ivConcern.setOnClickListener {
            ifLogin("游戏详情-[关注]") {
                if (viewModel.meLiveData.value?.isGameConcerned == true) {
                    DialogHelper.showCancelDialog(requireContext(), {
                        viewModel.concernCommand(false)
                    })
                } else {
                    viewModel.concernCommand(true)
                }
            }
        }
        downloadBinding.tvConcern.setOnClickListener { downloadBinding.ivConcern.performClick() }
        downloadBinding.ivReserve.setOnClickListener {
            if (gameEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity!!)) {
                startActivity(SimulatorGameActivity.getIntent(requireContext()))
                return@setOnClickListener
            }
            CheckLoginUtils.checkLogin(requireContext(), "游戏详情") {
                if (!ReservationRepository.thisGameHasBeenReserved(gameEntity?.id ?: "")) {
                    ReservationHelper.reserve(
                        requireContext(),
                        gameEntity,
                        callback = {
                            LogUtils.logReservation(gameEntity, traceEvent)
                            DetailDownloadUtils.updateViewHolder(detailViewHolder)
                            if (downloadBinding.ivReserve.visibility == View.VISIBLE) {
                                showReserveBtn(isShowReserveBtn())
                            }
                        }
                    )
                } else {
                    ReservationHelper.showCancelReservationDialog(requireContext(), gameEntity) {
                        ReservationHelper.cancelReservation(gameEntity!!) {
                            DetailDownloadUtils.updateViewHolder(detailViewHolder)
                            showReserveBtn(isShowReserveBtn())
                        }
                    }
                }
            }
        }
        downloadBinding.tvReserve.setOnClickListener { downloadBinding.ivReserve.performClick() }
        downloadBinding.ivSwitch.setOnClickListener {
            val intent = ShellActivity.getIntent(requireContext(), ShellActivity.Type.SWITCH_INSTALL_METHOD, null)
            requireActivity().startActivity(intent)
        }
        downloadBinding.tvSwitch.setOnClickListener { downloadBinding.ivSwitch.performClick() }
        binding.popReserverGuide.closeIv.setOnClickListener {
            showReserveGuide(false)
        }
        recommendBinding.recommendCloseIv.setOnClickListener {
            hideRecommendView(true)
        }
    }

    private fun updateConcernMenuIcon(isConcerned: Boolean) {
        if (isConcerned) {
            downloadBinding.tvConcern.text = "已关注"
            downloadBinding.ivConcern.setImageResource(R.drawable.ic_gamedetail_concerned)
        } else {
            downloadBinding.tvConcern.text = "关注"
            downloadBinding.ivConcern.setImageResource(R.drawable.ic_gamedetail_concern)
        }
    }

    private fun updateDownloadIcon() {
        updateDownloadCountHint(packageViewModel.filterSameUpdateLiveData.value)

        val downloadMenuView = bodyBinding.actionMenuView.menu.findItem(R.id.menu_download).actionView
        downloadCountHint = downloadMenuView?.findViewById(R.id.menu_download_count_hint)
        downloadCountHint?.typeface =
            Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH)
    }

    private fun updateDownloadCountHint(updateList: List<GameUpdateEntity>?) {
        val count = DownloadManager.getInstance().getDownloadOrUpdateCount(updateList)
        val params = downloadCountHint?.layoutParams
        params?.width = if (count.isNullOrEmpty()) 6F.dip2px() else ConstraintLayout.LayoutParams.WRAP_CONTENT
        params?.height = if (count.isNullOrEmpty()) 6F.dip2px() else 14F.dip2px()
        (params as? ViewGroup.MarginLayoutParams)?.setMargins(
            0,
            if (count.isNullOrEmpty()) 0 else (-4F).dip2px(),
            if (count.isNullOrEmpty()) (-4F).dip2px() else (-8F).dip2px(),
            0
        )
        downloadCountHint?.setPadding(
            if (count.isNullOrEmpty()) 0 else 4F.dip2px(),
            0,
            if (count.isNullOrEmpty()) 0 else 4F.dip2px(),
            0
        )
        downloadCountHint?.minWidth = if (count.isNullOrEmpty()) 0 else 14F.dip2px()
        downloadCountHint?.layoutParams = params

        downloadCountHint?.goneIf(count == null)
        downloadCountHint?.text = count.toString()
    }

    private fun controlReserveBtn() {
        if (isShowReserveBtn()) {
            showReserveBtn(true)
            val isFirstIn = SPUtils.getBoolean(Constants.SP_GAME_DETAIL_RESERVE_GUIDE, true)
            val gameGuidePopupEntity = Config.getGameGuidePopupEntity()
            if (isFirstIn && gameEntity?.downloadOffStatus == null) {
                showReserveGuide(true)
                SPUtils.setBoolean(Constants.SP_GAME_DETAIL_RESERVE_GUIDE, false)
            }
            if (gameGuidePopupEntity != null) {
                showReserveGuide(false)
                SPUtils.setBoolean(Constants.SP_GAME_DETAIL_RESERVE_GUIDE, false)
            }
        } else {
            showReserveBtn(false)
        }
    }

    private fun showReserveBtn(isShow: Boolean = false) {
        if (gameEntity != null && SimulatorGameManager.isSimulatorGame(gameEntity!!)) {
            downloadBinding.ivReserve.visibility = View.VISIBLE
            downloadBinding.tvReserve.visibility = View.VISIBLE
            downloadBinding.tvReserve.text = "管理"
            downloadBinding.ivReserve.setImageResource(R.drawable.ic_gamedetail_simulator_manage)
            return
        }

        if (isShow) {
            downloadBinding.ivReserve.visibility = View.VISIBLE
            downloadBinding.tvReserve.visibility = View.VISIBLE
            if (ReservationRepository.thisGameHasBeenReserved(gameEntity?.id ?: "")) {
                downloadBinding.tvReserve.text = "已预约"
                downloadBinding.ivReserve.setImageResource(R.drawable.ic_gamedetail_reserved)
            } else {
                downloadBinding.tvReserve.text = "预约"
                downloadBinding.ivReserve.setImageResource(R.drawable.ic_gamedetail_reserve)
            }
        } else {
            downloadBinding.ivReserve.visibility = View.GONE
            downloadBinding.tvReserve.visibility = View.GONE
        }
    }

    private fun showReserveGuide(isShow: Boolean = false) {
        binding.popReserverGuide.reserveGuideContainer.visibility = if (isShow) View.VISIBLE else View.GONE
    }

    private fun isShowReserveBtn(): Boolean {
        if (gameEntity == null || gameDetailSetting == null) return false
        if (gameEntity!!.getApk().isEmpty() ||
            gameEntity!!.downloadOffStatus != null ||
            !gameDetailSetting!!.appointmentSwitchStatus
        ) return false
        return true
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(reuse: EBReuse) {
        if ("download" == reuse.type) {
            downloadBinding.detailProgressbar.performClick()
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(status: EBDownloadStatus) {
        updateDownloadCountHint(packageViewModel.filterSameUpdateLiveData.value)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(status: EBTypeChange) {
        if (status.type == EB_SCROLLING) {
            hideRecommendView()
        }
    }

    // 接收下载被删除消息
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEvent(status: EBDownloadStatus) {
        if ("delete" == status.status && gameEntity != null && gameEntity!!.getApk().size == 1) {
            val url = gameEntity!!.getApk()[0].url
            if (status.url == url) {
                DetailDownloadUtils.updateViewHolder(detailViewHolder)
            }
        }
    }

    // 接受安装、卸载消息
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(busFour: EBPackage) {
        if (gameEntity != null && gameEntity!!.getApk().size > 0) {
            for (apk in gameEntity!!.getApk()) {
                if (busFour.packageName == apk.packageName) {
                    ApkActiveUtils.filterHideApk(gameEntity)
                    DetailDownloadUtils.updateViewHolder(detailViewHolder)
                    viewModel.updateGameStatus()
                }
            }
        }
    }

    // 关注事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(changed: EBConcernChanged) {
        if (gameEntity != null && changed.isSingle && changed.gameId == gameEntity!!.id) {
            val meEntity = viewModel.meLiveData.value ?: return
            viewModel.meLiveData.postValue(meEntity.apply { isGameConcerned = changed.isConcern })
        }
    }

    private fun loadErrorControl(exception: HttpException?) {
        binding.errorToolbarContainer.visibility = View.VISIBLE
        binding.bodyContainer.viewPager.visibility = View.GONE
        binding.errorReuseToolbar.backBtn.setOnClickListener { requireActivity().finish() }

        if (exception != null && exception.code() == 404) {
            viewModel.removeFromHistory()
            binding.reuseNoConnection.reuseNoConnection.visibility = View.GONE
            binding.reuseNoneData.reuseNoneData.visibility = View.GONE
            binding.reuseDataException.reuseDataException.visibility = View.VISIBLE
            downloadBinding.ivConcern.visibility = View.GONE
            downloadBinding.tvConcern.visibility = View.GONE
            toast("内容可能已被删除")
        } else {
            binding.reuseNoConnection.reuseNoConnection.visibility = View.VISIBLE
            binding.reuseNoneData.reuseNoneData.visibility = View.GONE
            binding.reuseDataException.reuseDataException.visibility = View.GONE
        }

        skeleton?.hide()
    }

    private fun showBrowserInstallHintIfNeeded() {
        if (BrowserInstallHelper.shouldShowGameDetailUseBrowserToInstallHint()
            && gameEntity?.isSplitXApk() != true
        ) {
            downloadBinding.browserInstallHintContainer.visibility = View.VISIBLE
            downloadBinding.browserInstallHintContainer.setOnClickListener {
                val intent = ShellActivity.getIntent(
                    requireContext(),
                    ShellActivity.Type.SWITCH_INSTALL_METHOD,
                    null
                )
                requireActivity().startActivity(intent)
                BrowserInstallHelper.logOrdinaryBrowserEvent(BrowserInstallHelper.Type.SWITCH_INSTALL_GUIDE_ACCESS)
            }
            val manufacturer = Build.MANUFACTURER.uppercase(Locale.CHINA)
            val hintText: String
            val closeHintText: String

            if (manufacturer == "OPPO" || manufacturer == "VIVO") {
                hintText =
                    if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) "当前安装方式为[浏览器安装]，点击切换安装方式" else "${manufacturer}手机如何解决安装需要密码"
                closeHintText =
                    "关闭后“切换安装方式”入口将显示在左下角，您也可以前往“我的光环-设置-切换安装方式”进行设置，或在“ 我的光环-帮助与反馈”查看相关问题"
            } else {
                hintText =
                    if (SPUtils.getBoolean(Constants.SP_USE_BROWSER_TO_INSTALL)) "当前安装方式为[浏览器安装]，点击切换安装方式" else "手机如何解决无法安装问题"
                closeHintText =
                    "关闭后“切换安装方式”入口将显示在左下角，您也可以前往“我的光环-设置-切换安装方式”进行设置"
            }

            downloadBinding.browserInstallHintTv.text = hintText
            downloadBinding.browserInstallHintCloseIv.enlargeTouchArea(16F.dip2px())
            downloadBinding.browserInstallHintCloseIv.setOnClickListener {
                DialogHelper.showDialog(
                    requireContext(),
                    "温馨提示",
                    closeHintText,
                    "确定",
                    "取消",
                    {
                        downloadBinding.browserInstallHintContainer.visibility = View.GONE
                        SPUtils.setBoolean(Constants.SP_SWITCH_INSTALL_VISIBLE, true)
                        downloadBinding.ivSwitch.visibility = View.VISIBLE
                        downloadBinding.tvSwitch.visibility = View.VISIBLE
                        BrowserInstallHelper.hideGameDetailUseBrowserToInstallHint()
                        BrowserInstallHelper.logOrdinaryBrowserEvent(BrowserInstallHelper.Type.SWITCH_INSTALL_GUIDE_QUIT)
                    }
                )
            }
        } else {
            downloadBinding.browserInstallHintContainer.visibility = View.GONE
        }
        if (SPUtils.getBoolean(Constants.SP_SWITCH_INSTALL_VISIBLE, false)) {
            downloadBinding.ivSwitch.visibility = View.VISIBLE
            downloadBinding.tvSwitch.visibility = View.VISIBLE
        } else {
            downloadBinding.ivSwitch.visibility = View.GONE
            downloadBinding.tvSwitch.visibility = View.GONE
        }
    }

    private fun controlInstallHint() {
        if (gameEntity != null) {
            val status = GameUtils.getDownloadBtnText(
                context = requireContext(),
                gameEntity = gameEntity!!,
                isFromList = false,
                fixedAsVGame = false,
                pluginLocation = PluginLocation.only_game
            )
            val isLaunch =
                (status == getString(com.gh.gamecenter.feature.R.string.launch) || status == getString(com.gh.gamecenter.feature.R.string.open))
            if (SPUtils.getBoolean(
                    Constants.SP_SHOULD_SHOW_GAME_DETAIL_INSTALL_GUIDE,
                    false
                ) && !gameEntity!!.isReservable
            ) {
                if (gameEntity!!.downloadOffText?.isEmpty() == true && !isLaunch) {
                    showInstallHint()
                } else {
                    hideInstallHint()
                }
            }
        }
    }

    private fun showInstallHint() {
        if (downloadBinding.installHintContainer.visibility == View.VISIBLE) return
        val gameGuidePopupEntity = Config.getGameGuidePopupEntity()
        if (gameGuidePopupEntity != null && SPUtils.getBoolean(Constants.SP_GAME_DETAIL_INSTALL_GUIDE, true)) {
            downloadBinding.installHintTv.text = gameGuidePopupEntity.content
            downloadBinding.installHintContainer.visibility = View.VISIBLE
            NewLogUtils.logGuidePopShow(gameGuidePopupEntity.id)
            downloadBinding.installHintContainer.setDebouncedClickListener {
                DirectUtils.directToLinkPage(requireContext(), gameGuidePopupEntity.jump, mEntrance, "游戏详情")
                NewLogUtils.logGuidePopLinkClick(
                    gameGuidePopupEntity.id,
                    gameGuidePopupEntity.jump.type,
                    gameGuidePopupEntity.jump.linkText
                )
            }
            downloadBinding.installHintCloseIv.enlargeTouchArea(16F.dip2px())
            downloadBinding.installHintCloseIv.setDebouncedClickListener {
                hideInstallHint()
                SPUtils.setBoolean(Constants.SP_GAME_DETAIL_INSTALL_GUIDE, false)
                NewLogUtils.logGuidePopClose(gameGuidePopupEntity.id)
            }
        }
    }

    private fun hideInstallHint() {
        downloadBinding.installHintContainer.visibility = View.GONE
    }

    private fun initRecommendUI() {
        val recommendPopupList = viewModel.recommendPopupLiveData.value
        recommendPopupEntity = RecommendPopupHelper.getRecommendPopup(viewModel.game, recommendPopupList) ?: return
        val popupDetail = recommendPopupEntity!!.popupDetail
        recommendBinding.recommendText.text = popupDetail.text
        if (popupDetail.images.isNotEmpty()) {
            ImageUtils.display(recommendBinding.recommendImage, popupDetail.images[0])
            recommendBinding.recommendImage.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
                override fun loaded() {
                    recommendBinding.recommendImage.post {
                        recommendBinding.recommendImage.layoutParams.apply {
                            width = 68f.dip2px()
                            height = (width / recommendBinding.recommendImage.aspectRatio).toInt()
                            recommendBinding.recommendImage.layoutParams = this
                        }
                    }
                }
            })
        } else {
            recommendBinding.recommendImage.visibility = View.GONE
            (recommendBinding.recommendText.layoutParams as ConstraintLayout.LayoutParams).apply {
                leftMargin = 16f.dip2px()
                recommendBinding.recommendText.layoutParams = this
            }
            recommendBinding.recommendText.maxWidth = 150f.dip2px()
        }
        recommendBinding.recommendLinkTv.text = popupDetail.link?.title
        recommendBinding.recommendLinkTv.setOnClickListener {
            popupDetail.link?.let {
                PageSwitchDataHelper.pushCurrentPageData(
                    hashMapOf(
                        Pair(
                            PageSwitchDataHelper.PAGE_GAME_DETAIL_RECOMMEND,
                            ""
                        )
                    )
                )
                DirectUtils.directToLinkPage(requireContext(), it, mEntrance, "游戏详情")
                LogUtils.uploadRecommendPopup(
                    "recommend_pop_link_click", recommendPopupEntity?.id, viewModel.game?.id
                        ?: "", viewModel.game?.name ?: "", it.type, it.text, "", ""
                )
            }
        }
    }

    private fun showRecommendView() {
        if (recommendPopupEntity == null) return
        if (!RecommendPopupHelper.checkFrequencyIsMatch(recommendPopupEntity!!)) return
        recommendBinding.recommendView.post {
            if (!isRecommendViewShow) {
                val width = recommendBinding.recommendView.measuredWidth.toFloat()
                recommendBinding.recommendView.x = -width
                recommendBinding.recommendView.visibility = View.VISIBLE
                recommendBinding.recommendView.animate().x(0f).setDuration(500).start()
                isRecommendViewShow = true
                RecommendPopupHelper.saveRecord(recommendPopupEntity!!)
                if (recommendPopupEntity!!.popupDetail.duration > 0) {
                    recommendDisposable =
                        countDownTimer(recommendPopupEntity!!.popupDetail.duration) { finish, _ ->
                            if (finish) hideRecommendView()
                        }
                }
                LogUtils.uploadRecommendPopup(
                    "recommend_pop_show", recommendPopupEntity?.id, viewModel.game?.id
                        ?: "", viewModel.game?.name ?: "", "", "", "", ""
                )
            }
        }
    }

    private fun hideRecommendView(isManuallyClose: Boolean = false) {
        recommendBinding.recommendView.post {
            if (isRecommendViewShow) {
                val width = recommendBinding.recommendView.measuredWidth.toFloat()
                recommendBinding.recommendView.animate().x(-width).setDuration(500).start()
                isRecommendViewShow = false
                recommendDisposable?.dispose()
                recommendDisposable = null
                if (isManuallyClose) {
                    LogUtils.uploadRecommendPopup(
                        "recommend_pop_close", recommendPopupEntity?.id, viewModel.game?.id
                            ?: "", viewModel.game?.name ?: "", "", "", "", ""
                    )
                }
            }
        }
    }

    /**
     * 当其它三个按钮不显示的时候才显示收藏按钮
     */
    private fun showConcernIconAtBottomBarIfAvailable() {
        val installSwitchViewIsNotVisible = !downloadBinding.ivSwitch.isVisible
        val reserveBtnIsNotVisible = !downloadBinding.ivReserve.isVisible
        val vmodeViewIsNotVisible = !downloadBinding.ivVmode.isVisible

        if (installSwitchViewIsNotVisible || reserveBtnIsNotVisible || vmodeViewIsNotVisible) {
            downloadBinding.ivConcern.visibility = View.VISIBLE
            downloadBinding.tvConcern.visibility = View.VISIBLE
        } else {
            downloadBinding.ivConcern.visibility = View.GONE
            downloadBinding.tvConcern.visibility = View.GONE

            showConcernOnMenu = true
        }
    }

    private fun showVModeIconAtBottomBarIfNeeded(simpleGame: SimpleGame?, gameEntity: GameEntity) {
        downloadBinding.groupVmode.goneIf(
            simpleGame == null
                    || gameEntity.isDualBtnModeEnabled()
                    || !VHelper.isVGameOn()
                    || RegionSettingHelper.shouldThisGameBeFiltered(simpleGame.id)
        ) {
            simpleGame?.let {
                val entity = it.toGameEntity()
                downloadBinding.ivVmode.displayGameIcon(entity)
                if (gameEntity.isVGame()) {
                    downloadBinding.tvVmode.text = "下载 >"
                    downloadBinding.ivVmodeBadge.setImageResource(R.drawable.ic_switch_game_download)
                } else {
                    downloadBinding.tvVmode.text = "畅玩 >"
                    downloadBinding.ivVmodeBadge.setImageResource(R.drawable.ic_switch_game_smooth)
                }

                downloadBinding.tvVmode.setOnClickListener { downloadBinding.ivVmode.performClick() }
                downloadBinding.ivVmode.enlargeTouchArea()
                downloadBinding.ivVmode.setOnClickListener { _ ->
                    val downloadStatus = when (entity.downloadStatus) {
                        Constants.V_GAME, Constants.V_GAME_32 -> "畅玩"
                        "demo" -> "试玩"
                        else -> "下载"
                    }
                    NewFlatLogUtils.logHaloFunGameDetailJumpClick(downloadStatus, simpleGame.id ?: "")
                    DirectUtils.directToGameDetail(requireContext(), it.id ?: "", entrance = mEntrance)
                }
            }
        }
    }

    /**
     * 特别下载弹窗是否可用，以下任一条件满足就不可用：
     * 1. 未配置特别下载弹窗
     * 2. 未获取到游戏详情数据
     * 3. 当前游戏 APK 不为 1 个
     * 4. 当前游戏类型不为畅玩
     * 5. 当前游戏不是双下载时使用本地下载进行下载
     * 6. 当前游戏支持加速
     */
    private fun isSpecialDownloadDialogAvailable(downloadEntity: DownloadEntity? = null): Boolean {
        if (Config.getNewApiSettingsEntity()?.install?.questionTip?.linkEntity == null) return false
        if (viewModel.detailDataListLiveData.value == null || gameEntity == null) return false
        if (gameEntity?.getApk()?.size != 1) return false
        if (downloadEntity?.asVGame() == true) return false
        if (downloadEntity?.isSimulatorGame() == true) return false
        if (downloadEntity?.isLocalDownloadInDualDownloadMode() == true) return false
        if (gameEntity?.canSpeed == true) return false
        return true
    }

    private fun updateSpecialDownloadDialogIcon(visible: Boolean) {
        binding.expandSpecialDownloadIv.goneIf(!visible)
    }

    private fun showSpecialDownloadDialog() {
        val dataList = viewModel.detailDataListLiveData.value ?: return

        val fragment = childFragmentManager.findFragmentByTag(TAG_SPECIAL_DOWNLOAD_DIALOG)
        val visibilityViewModel: SpecialDownloadVisibilityViewModel = viewModelProviderFromParent()

        if (fragment == null) {
            if (!visibilityViewModel.specialDownloadVisibleLiveData.hasObservers()) {
                visibilityViewModel.specialDownloadVisibleLiveData.observe(viewLifecycleOwner) {
                    updateSpecialDownloadDialogIcon(visible = !it)
                }
            }

            SpecialDownloadDialogFragment.newInstance(
                gameEntity!!,
                Config.getNewApiSettingsEntity()?.install?.questionTip?.linkEntity ?: LinkEntity(),
                gameEntity?.zone?.link,
                dataList.firstOrNull { it.linkLibao != null }?.linkLibao,
                dataList.firstOrNull { it.linkServer != null }?.linkServer
            ).show(childFragmentManager, TAG_SPECIAL_DOWNLOAD_DIALOG)
        }
    }

    private fun isSpecialDownloadDetailFragmentIsShowing(): Boolean {
        return childFragmentManager.findFragmentByTag(TAG_SPECIAL_DOWNLOAD_DIALOG) != null
    }

    // 更新分割线样式
    private fun updateDivider() {
        if (mIsDarkModeOn) {
            binding.divider.background = com.gh.gamecenter.common.R.color.ui_divider.toDrawable(requireContext())
            binding.divider.updateLayoutParams {
                height = 1
                width = LayoutParams.MATCH_PARENT
            }
        } else {
            binding.divider.background = R.drawable.shadow.toDrawable(requireContext())
            binding.divider.updateLayoutParams {
                height = 7F.dip2px()
                width = LayoutParams.MATCH_PARENT
            }
        }
    }


    override fun scrollToTop() {
        val fragment = fragmentsList.safelyGetInRelease(bodyBinding.viewPager.currentItem)
        if (fragment is IScrollable && fragment.isAdded) {
            fragment.scrollToTop()
        }
    }

    override fun onBackPressed(): Boolean {
        if (acceleratorUiHelper.onBack()) {
            return true
        }
        return when (val fragment = fragmentsList.getOrNull(bodyBinding.viewPager.currentItem)) {
            is GameDetailFragment -> {
                fragment.onBackPressed()
            }

            is WebFragment -> {
                fragment.onBackPressed()
            }

            else -> {
                super.onBackPressed()
            }
        }
    }

    private fun initSkeleton() {
        skeleton = Skeleton.bind(binding.listSkeleton)
            .shimmer(true)
            .angle(Constants.SHIMMER_ANGLE)
            .color(com.gh.gamecenter.common.R.color.ui_skeleton_highlight)
            .duration(Constants.SHIMMER_DURATION)
            .maskWidth(Constants.MASK_WIDTH)
            .gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
            .load(R.layout.fragment_game_detail_skeleton)
            .show()
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        for (i in 0 until tabEntityList.size) {
            val tab = bodyBinding.tabLayout.getTabAt(i) ?: continue
            updateTabStyle(tab, i == bodyBinding.viewPager.currentItem)
        }
        moreMenuItem?.setIcon(R.drawable.ic_menu_more)
        downloadMenuIcon?.setImageResource(R.drawable.toolbar_download)
        if (::viewModel.isInitialized) {
            updateConcernMenuIcon(viewModel.meLiveData.value?.isGameConcerned ?: false)
            if (gameEntity != null) {
                val viewHolder = detailViewHolder
                viewHolder.downloadPb.buttonStyle = detailViewHolder.downloadPb.buttonStyle
                if (viewHolder.downloadTips.isVisible) {
                    viewHolder.downloadTips.setDownloadTipsAnimation(detailViewHolder.downloadTips.isAnimating)
                }
            }
        }
        controlReserveBtn()
        // 更新分割线样式
        updateDivider()
        binding.detailLlBottom.detailLlBottom.setBackgroundColor(
            com.gh.gamecenter.common.R.color.ui_background.toColor(
                requireContext()
            )
        )
        binding.errorReuseToolbar.normalToolbar.setBackgroundColor(
            com.gh.gamecenter.common.R.color.ui_surface.toColor(
                requireContext()
            )
        )
        initSkeleton()
        skeleton?.hide()
    }

    companion object {
        const val EB_SCROLLING = "EB_SCROLLING"

        private const val SP_OPENED_DIALOG_TIME_PREFIX = "opened_dialog_time_prefix_"
        private const val LAST_SELECTED_POSITION = "last_selected_position"
        private const val SP_HAS_ENTER_ARCHIVE_GAME_DETAIL_PREFIX = "has_enter_archive_game_detail_prefix_"

        private const val TAG_SPECIAL_DOWNLOAD_DIALOG = "special_download_dialog"
    }
}