package com.gh.gamecenter.gamedetail

import android.animation.Animator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.*
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextUtils
import android.view.*
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.children
import androidx.core.view.isVisible
import androidx.core.widget.TextViewCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.viewpager2.widget.ViewPager2
import com.ethanhua.skeleton.Skeleton
import com.ethanhua.skeleton.ViewSkeletonScreen
import com.gh.common.constant.Config
import com.gh.common.databind.BindingAdapters
import com.gh.common.exposure.ExposureManager
import com.gh.common.filter.RegionSettingHelper
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.view.FlexLinearLayout
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.*
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.BaseFragment_TabLayout
import com.gh.gamecenter.common.base.fragment.ToolbarFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.eventbus.EBReuse
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.*
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.eventbus.*
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.entity.TagStyleEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.gamecenter.feature.utils.ApkActiveUtils
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.gamedetail.cloudarchive.CloudArchiveFragment
import com.gh.gamecenter.gamedetail.desc.DescFragment
import com.gh.gamecenter.gamedetail.dialog.GameBigEventDialog
import com.gh.gamecenter.gamedetail.dialog.GameDetailMoreDialog
import com.gh.gamecenter.gamedetail.dialog.GameTagsDialog
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity
import com.gh.gamecenter.gamedetail.entity.Video
import com.gh.gamecenter.gamedetail.fuli.FuLiFragment
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity
import com.gh.gamecenter.gamedetail.rating.RatingFragment
import com.gh.gamecenter.gamedetail.video.TopVideoView
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.login.user.UserViewModel
import com.gh.gamecenter.packagehelper.PackageViewModel
import com.gh.gamecenter.simulatorgame.SimulatorGameActivity
import com.gh.gamecenter.tag.TagsActivity
import com.gh.gamecenter.video.detail.CustomManager
import com.gh.vspace.VHelper
import com.google.android.material.appbar.AppBarLayout
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 com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
import com.shuyu.gsyvideoplayer.utils.OrientationUtils
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import retrofit2.HttpException
import java.lang.ref.WeakReference
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.abs

class GameDetailFragment : ToolbarFragment(), IScrollable {

    private var mDownloadMenuIcon: ImageView? = null
    private var mDownloadCountHint: TextView? = null
    private var mSkeleton: ViewSkeletonScreen? = null
    private var mGameEntity: GameEntity? = null
    private var mDownloadEntity: DownloadEntity? = null
    private var mNewGameDetailEntity: NewGameDetailEntity? = null
    private var mOrientationUtils: OrientationUtils? = null
    private var mMoreMenuItem: MenuItem? = null
    private var mSearchMenuItem: MenuItem? = null
    private var mDownloadMenuItem: MenuItem? = null
    private var mTraceEvent: ExposureEvent? = null
    private var mIsTouchScreen = false
    private var mIsShowKaifuHint: Boolean = false
    private var mIsScrollToKaiFu: Boolean = false
    private var mAutoDownload: Boolean = false
    private var mSkipGameComment: Boolean = false
    private var mIsOpenPlatformWindow: Boolean = false
    private var mCurVpPosition: Int = 0
    private var mMaxWidth: Int = 0
    private var mDestinationTab = -1 // 供快捷跳转到某个 tab 使用
    private var mIsPauseTopVideo = false
    private var mIsRecommendViewShow = false
    private var mRecommendDisposable: Disposable? = null
    private var mRecommendPopupEntity: RecommendPopupEntity? = null
    private var mTabClickEvent: Pair<Long, String> = Pair(0L, "")
    private var mContentCardServerVp: ViewPager2? = null
    private var mIsPlayingWhenPause = false // 判断执行onPause时视频是否在播放中

    private lateinit var mBinding: FragmentGamedetailBinding
    private lateinit var mVideoBinding: PieceGameDetailVideoBinding
    private lateinit var mBodyBinding: GamedetailBodyBinding
    private lateinit var mDownloadBinding: DetailDownloadItemBinding
    private lateinit var mRecommendBinding: LayoutGameDetailRecommendViewBinding

    private lateinit var mViewModel: GameDetailViewModel
    private lateinit var mPackageViewModel: PackageViewModel
    private lateinit var mUserViewModel: UserViewModel

    private var mShowConcernOnMenu = false

    private val mFragmentsList = ArrayList<Fragment>()
    private val mTabTitleList = ArrayList<String>()
    private val mTabTypeList = ArrayList<String>() // tab 类型的列表，用于确定某个类型的 tab 在第几个位置
    private val mLooperHandle = LooperHandle(this)
    private val mServerLooperKey = 123

    private val dataWatcher = object : DataWatcher() {
        override fun onDataChanged(downloadEntity: DownloadEntity) {
            if (downloadEntity.gameId == mViewModel.gameId) {
                if (downloadEntity.status == DownloadStatus.add
                    || downloadEntity.status == DownloadStatus.done
                    || downloadEntity.status == DownloadStatus.downloading
                    || downloadEntity.status == DownloadStatus.pause
                    || downloadEntity.status == DownloadStatus.redirected
                ) {
                    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 (mGameEntity?.getApk()?.size == 1) {
                    if ("pause" != DownloadManager.getInstance().getStatus(downloadEntity.url)?.status) {
                        mDownloadEntity = downloadEntity
                        DetailDownloadUtils.detailInvalidate(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) {
                        mRecommendBinding.recommendView.postDelayed({ showRecommendView() }, 500)
                        if (gameDetailRecommendMeta.isNotEmpty() && mRecommendPopupEntity != null) {
                            LogUtils.uploadRecommendPopup(
                                "recommend_pop_download",
                                mRecommendPopupEntity?.id,
                                mViewModel.game?.id ?: "",
                                mViewModel.game?.name ?: "",
                                mRecommendPopupEntity?.popupDetail?.link?.type,
                                mRecommendPopupEntity?.popupDetail?.link?.text,
                                downloadEntity.gameId,
                                downloadEntity.name
                            )
                        }
                    } else if (downloadEntity.status == DownloadStatus.done) {
                        hideRecommendView()
                        if (gameDetailRecommendMeta.isNotEmpty() && mRecommendPopupEntity != null) {
                            LogUtils.uploadRecommendPopup(
                                "recommend_pop_download_complete",
                                mRecommendPopupEntity?.id,
                                mViewModel.game?.id ?: "",
                                mViewModel.game?.name ?: "",
                                mRecommendPopupEntity?.popupDetail?.link?.type,
                                mRecommendPopupEntity?.popupDetail?.link?.text,
                                downloadEntity.gameId,
                                downloadEntity.name
                            )
                        }
                    }
                } else if ((mGameEntity?.getApk()?.size ?: 0) > 1) {
                    when (downloadEntity.status) {
                        DownloadStatus.downloading -> {
                            if (detailViewHolder.mDownloadTips.visibility == View.GONE || !detailViewHolder.mDownloadTips.isAnimating) {
                                detailViewHolder.mDownloadTips.visibility = View.VISIBLE
                                detailViewHolder.mDownloadTips.setDownloadTipsAnimation(true)
                            }
                        }

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

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

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

    // 下载按钮ViewHolder
    // 每次获取需要重新创建, 防止数据刷新
    private val detailViewHolder: DetailViewHolder
        get() =
            DetailViewHolder(
                mCachedView,
                mGameEntity,
                mDownloadEntity,
                false,
                mEntrance,
                "游戏详情",
                mGameEntity!!.name,
                mTraceEvent
            )

    private val contentCardClick: (contentCard: ContentCardEntity) -> Unit = { contentCardEntity ->
        NewFlatLogUtils.logGameDetailGameContentCardClick(
            contentCardEntity.title ?: "",
            mGameEntity?.name ?: "",
            mGameEntity?.id ?: "",
            contentCardEntity.type ?: "",
            contentCardEntity.link ?: "",
            contentCardEntity.text ?: ""
        )
        val path = "游戏详情->内容卡片"
        when (contentCardEntity.type) {
            "func_server" -> {
                if (contentCardEntity.server != null) {
                    requireContext().startActivity(
                        ServersCalendarActivity.getIntent(
                            requireContext(),
                            mViewModel.game!!, contentCardEntity.server!!,
                            mNewGameDetailEntity?.me
                        )
                    )
                }
            }

            "func_libao" -> {
                mBodyBinding.gamedetailVp.currentItem = 0
                mBodyBinding.gamedetailAppbar.setExpanded(false, true)
                val fragment = mFragmentsList[0]
                if (fragment is DescFragment && fragment.isAdded) {
                    fragment.scrollToLibao()
                }
            }

            "func_related_version" -> {
                mBodyBinding.gamedetailVp.currentItem = 0
                mBodyBinding.gamedetailAppbar.setExpanded(false, true)
                val fragment = mFragmentsList[0]
                if (fragment is DescFragment && fragment.isAdded) {
                    fragment.scrollToRelatedVersion()
                }
            }

            "func_zone" -> {
                val gameDetailEntity = mViewModel.gameDetailLiveData.value?.data
                if (contentCardEntity.zoneTab && gameDetailEntity?.zone != null && gameDetailEntity.zone!!.style == "link") {
                    requireContext().startActivity(
                        WebActivity.getIntent(
                            requireContext(),
                            gameDetailEntity.zone!!.link,
                            true
                        )
                    )
                }
            }

            "func_bbs" -> {
                val funcBbs = contentCardEntity.funcBbs
                funcBbs?.let {
                    DirectUtils.directForumDetail(requireContext(), it.link, path)
                }
            }

            "func_tool_kit" -> {
                if (contentCardEntity.toolkit.isNotEmpty()) {
                    contentCardEntity.toolkit.safelyGetInRelease(0)?.let {
                        val url = it.url
                        if (url != null && url.contains(Config.URL_ARTICLE)) {
                            val newsId = url.substring(url.lastIndexOf("/") + 1, url.length - 5) // 5: ".html"
                            val intent = NewsDetailActivity.getIntentById(requireContext(), newsId, path)
                            requireContext().startActivity(intent)
                        } else {
                            requireContext().startActivity(
                                WebActivity.getWebByCollectionTools(
                                    requireContext(),
                                    it,
                                    false
                                )
                            )
                        }
                    }
                }
            }

            else -> DirectUtils.directToLinkPage(
                requireContext(),
                contentCardEntity.toLinkEntity(),
                mEntrance,
                path,
                ExposureEvent.createEvent(
                    null,
                    listOf(
                        ExposureSource("游戏详情", mGameEntity?.id ?: ""),
                        ExposureSource("内容卡片", contentCardEntity.id)
                    )
                )
            )
        }
    }

    override fun getLayoutId(): Int = 0
    override fun getInflatedLayout(): View {
        return FragmentGamedetailBinding.inflate(LayoutInflater.from(requireContext())).apply {
            mBinding = this
            mBodyBinding = mBinding.bodyContainer
            mVideoBinding = mBodyBinding.gameDetailVideo
            mDownloadBinding = mBinding.detailLlBottom
            mRecommendBinding = mBinding.gameDetailRecommendView
        }.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        mBodyBinding.run {
            toolbar.inflateMenu(R.menu.menu_game_detail)
            mMoreMenuItem = toolbar.menu.findItem(R.id.menu_more)
            mSearchMenuItem = toolbar.menu.findItem(R.id.menu_search)
            mDownloadMenuItem = toolbar.menu.findItem(R.id.menu_download)
        }

        mDownloadMenuIcon = mDownloadMenuItem?.actionView?.findViewById(R.id.menu_download_iv)

        val menuItemClickListener = MenuItem.OnMenuItemClickListener {
            consume {
                when (it.itemId) {
                    R.id.menu_more -> {
                        if (mGameEntity != null && mNewGameDetailEntity != null) {
                            GameDetailMoreDialog.showMoreDialog(
                                requireActivity() as AppCompatActivity,
                                mGameEntity,
                                mNewGameDetailEntity?.shortId ?: "",
                                mShowConcernOnMenu,
                                mNewGameDetailEntity!!.me.isGameConcerned
                            )
                            MtaHelper.onEvent("游戏详情_新", "更多按钮", mViewModel.game?.name ?: "")
                        }
                    }

                    R.id.menu_search -> {
                        LogUtils.uploadSearchGame("access_to_search", "游戏详情", "", "")
                        val intent = SearchActivity.getIntent(requireContext(), false, "", "游戏详情", "游戏详情")
                        startActivity(intent)
                    }
                }
            }
        }

        mMoreMenuItem?.setOnMenuItemClickListener(menuItemClickListener)
        mSearchMenuItem?.setOnMenuItemClickListener(menuItemClickListener)
        mDownloadMenuItem?.actionView?.setOnClickListener {
            MtaHelper.onEvent("游戏详情_新", "下载管理图标", mViewModel.game?.name ?: "")
            val intent = DownloadManagerActivity.getDownloadMangerIntent(requireContext(), mEntrance)
            startActivity(intent)
        }

        updateDownloadIcon()
    }

    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 onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        savedInstanceState?.let { mDestinationTab = it.getInt(LAST_SELECTED_POSITION) }
        mBinding.reuseNoneData.reuseNoneDataTv.text = "页面不见了"
        mBodyBinding.gamedetailVp.setScrollable(true)
        mBodyBinding.gamedetailVp.offscreenPageLimit = 5

        mMaxWidth = resources.displayMetrics.widthPixels - DisplayUtils.dip2px(40f)

        val args = arguments ?: Bundle()
        mAutoDownload = args.getBoolean(EntranceConsts.KEY_AUTO_DOWNLOAD)
        mTraceEvent = args.getParcelable(EntranceConsts.KEY_TRACE_EVENT)
        mSkipGameComment = args.getBoolean(EntranceConsts.KEY_SKIP_GAME_COMMENT)
        mIsOpenPlatformWindow = args.getBoolean(EntranceConsts.KEY_OPEN_PLATFORM_WINDOW)

        mSkeleton = Skeleton.bind(mBinding.listSkeleton)
            .shimmer(true)
            .angle(Constants.SHIMMER_ANGLE)
            .color(R.color.skeleton_shimmer_color)
            .duration(Constants.SHIMMER_DURATION)
            .maskWidth(Constants.MASK_WIDTH)
            .gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
            .load(R.layout.fragment_gamedetail_skeleton)
            .show()

        val factory = GameDetailViewModel.Factory(
            HaloApp.getInstance().application,
            args.getString(EntranceConsts.KEY_GAMEID),
            args.getParcelable(GameEntity.TAG)
        )
        mViewModel = viewModelProviderFromParent(factory)
        mPackageViewModel = viewModelProvider(PackageViewModel.Factory())
        mUserViewModel = viewModelProvider(UserViewModel.Factory(HaloApp.getInstance().application))

        mBodyBinding.gamedetailVp.doOnPageSelected { position ->
            if (!isAdded) return@doOnPageSelected

            mBinding.gamedetailKaifuHint.visibleIf(mIsShowKaifuHint && position == getTabPositionFromTabType(TAB_TRENDS))

            val bbsPosition = getTabPositionFromTabType(TAB_BBS)
            val trendsPosition = getTabPositionFromTabType(TAB_TRENDS)

            if (mNewGameDetailEntity?.bbsTab != null && position == bbsPosition) {
                DirectUtils.directToLinkPage(
                    requireContext(),
                    mNewGameDetailEntity?.bbsTab!!,
                    "游戏详情",
                    ""
                )
                LogUtils.uploadAccessToBbs(mNewGameDetailEntity?.bbsTab?.link, "游戏详情")
                mBodyBinding.gamedetailVp.postDelayed({
                    if (mBodyBinding.gamedetailVp.currentItem == mTabTitleList.size - 1) {
                        mBodyBinding.gamedetailVp.currentItem = mCurVpPosition
                    }
                }, 200)
            } else if (mNewGameDetailEntity?.zone != null && mNewGameDetailEntity?.zone?.style != "default" && position == trendsPosition && mNewGameDetailEntity?.bbsTab != null) {
                // 跳转论坛-专区
                val entrance = if (mDestinationTab == getTabPositionFromTabType(TAB_TRENDS)) {
                    if (mEntrance.contains("搜索")) "搜索页面" else "其他"
                } else "游戏详情页"
                mNewGameDetailEntity?.bbsTab?.link?.let {
                    startActivity(
                        ForumDetailActivity.getTrendsIntent(
                            requireContext(),
                            it,
                            entrance
                        )
                    )
                }
                mBodyBinding.gamedetailVp.postDelayed({
                    if (mBodyBinding.gamedetailVp.currentItem == trendsPosition) {
                        mBodyBinding.gamedetailVp.currentItem = mCurVpPosition
                    }
                }, 200)
            } else {
                mCurVpPosition = position
            }
            hideRecommendView()
        }

        mBodyBinding.gamedetailAppbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
            // requireContext():not attached to context
            if (!isAdded) return@OnOffsetChangedListener

            val absVerticalOffset = abs(verticalOffset)
            val total = appBarLayout.totalScrollRange

            mBodyBinding.run {
                if (mViewModel.displayTopVideo) {
                    // 每次设置 title 都会触发 requestLayout，最后造成 OOM，这里过滤下，相同文字的时候不处理
                    if (absVerticalOffset > total / 2) {
                        if (titleTv.text.isNullOrEmpty()) {
                            titleTv.text = mGameEntity?.name ?: ""
                            gamedetailThumbSmall.visibility = View.VISIBLE
                            updateToolbarStyle(isToolbarWhite = true)
                        }
                    } else {
                        if (!titleTv.text.isNullOrEmpty()) {
                            titleTv.text = ""
                            gamedetailThumbSmall.visibility = View.GONE
                            updateToolbarStyle(isToolbarWhite = false)
                        }
                    }
                } else {
                    if (absVerticalOffset > total * 0.5) {
                        if (titleTv.text.isNullOrEmpty()) {
                            titleTv.text = mGameEntity?.name ?: ""
                            gamedetailThumbSmall.visibility = View.VISIBLE
                        }
                    } else {
                        if (!titleTv.text.isNullOrEmpty()) {
                            titleTv.text = ""
                            gamedetailThumbSmall.visibility = View.GONE
                        }
                    }
                }
            }

            if (absVerticalOffset == total) {
                if (mVideoBinding.player.currentState == GSYVideoView.CURRENT_STATE_PLAYING) {
                    pauseVideo()
                    mIsPauseTopVideo = true
                }
                mBodyBinding.toolbar.setTitleTextColor(ContextCompat.getColor(requireContext(), R.color.black))

                if (mIsScrollToKaiFu) {
                    mIsScrollToKaiFu = false
                    EventBus.getDefault().post(EBReuse(SCROLL_TO_KAIFU))
                }
            } else if (mIsPauseTopVideo && absVerticalOffset == 0 && mVideoBinding.player.currentState == GSYVideoView.CURRENT_STATE_PAUSE) {
                resumeVideo()
                mIsPauseTopVideo = false
            }
        })

        observeData()
    }

    private fun initGameSubtitle(
        gameTitleTv: TextView,
        gameSubtitle: String,
        gameSubtitleStyle: TagStyleEntity? = null,
        advanceDownload: Boolean = false
    ) {
        gameTitleTv.post {
            if (!isAdded) return@post
            gameTitleTv.run {
                var lastPosX = 0F
                tryCatchInRelease {
                    lastPosX = layout.getSecondaryHorizontal(text.length)
                }
                var remainWidth = (width - lastPosX).toInt()
                val isFullGameName = (lineCount == 2 && layout.getEllipsisCount(1) == 0)
                val tagMaxWidth = if (isFullGameName) remainWidth - 4F.dip2px() else width
                val tagLayout = FrameLayout(context)
                val tagView = TextView(context).apply {
                    layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, 14F.dip2px())
                    text = if (advanceDownload) "预下载" else gameSubtitle
                    textSize = 10F
                    setPadding(2F.dip2px(), 0, 2F.dip2px(), 0)
                    setSingleLine()
                    ellipsize = TextUtils.TruncateAt.END
                    maxWidth = tagMaxWidth
                    if (gameSubtitleStyle != null && !advanceDownload) {
                        setTextColor("#${gameSubtitleStyle.color}".hexStringToIntColor())
                        background = GradientDrawable().apply {
                            cornerRadius = 2F.dip2px().toFloat()
                            if (gameSubtitleStyle.style == "border") {
                                setColor(Color.TRANSPARENT)
                                setStroke(0.5F.dip2px(), "#${gameSubtitleStyle.background}".hexStringToIntColor())
                            } else {
                                shape = GradientDrawable.RECTANGLE
                                setColor("#${gameSubtitleStyle.background}".hexStringToIntColor())
                            }
                        }
                    } else {
                        setTextColor(R.color.text_subtitle.toColor(requireContext()))
                        background = R.drawable.bg_advance_download_game_subtitle.toDrawable(requireContext())
                    }
                }
                tagView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
                if (tagView.layout.getEllipsisCount(0) > 0 && !isFullGameName) {
                    tagView.maxWidth = width
                    tagView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
                }
                var displayName = text
                var changeDisplayName = false
                if ((lineCount == 2 && layout.getEllipsisCount(1) > 0) || (lineCount == 2 && tagView.measuredWidth > remainWidth)) {
                    val textCount = calculateTextCountByWidth(this, 2 * gameTitleTv.width - tagView.measuredWidth) - 1
                    if (textCount in text.indices) {
                        displayName = text.substring(0, textCount) + "…"
                        changeDisplayName = true
                    }
                }
                text = displayName
                tryCatchInRelease {
                    lastPosX = layout.getSecondaryHorizontal(text.length)
                }
                remainWidth = (width - lastPosX).toInt()
                tagLayout.addView(
                    tagView,
                    FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, 14F.dip2px()).apply {
                        leftMargin = if (remainWidth >= tagView.measuredWidth) 4F.dip2px() else 0
                    })
                val tagBitmap = tagLayout.convertViewToBitmap()
                if (changeDisplayName) ellipsize = null
                text = SpannableStringBuilder("$displayName ").apply {
                    tagBitmap?.let {
                        setSpan(
                            CenterImageSpan(
                                context,
                                it
                            ), displayName.length, displayName.length + 1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE
                        )
                    }
                }
                post {
                    subtractGameNameIfNeeded(this, displayName, tagLayout)
                }
            }
        }
    }

    private fun subtractGameNameIfNeeded(textView: TextView, name: CharSequence, tagLayout: FrameLayout) {
        try {
            if (!isAdded) return
            textView.run {
                if (lineCount > 2 || (layout != null && layout.getEllipsisCount(1) > 0)) {
                    val displayName = name.substring(0, name.length - 2) + "…"
                    text = displayName
                    if (tagLayout.getChildAt(0) != null) {
                        val tagView = tagLayout.getChildAt(0)
                        tagView.layoutParams = (tagView.layoutParams as FrameLayout.LayoutParams).apply {
                            setMargins(if (lineCount == 1) 0 else 4F.dip2px(), 0, 0, 0)
                        }
                    }
                    val tagBitmap = tagLayout.convertViewToBitmap()
                    text = SpannableStringBuilder("$displayName ").apply {
                        tagBitmap?.let {
                            setSpan(
                                CenterImageSpan(
                                    context,
                                    it
                                ), displayName.length, displayName.length + 1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE
                            )
                        }
                    }
                    post {
                        subtractGameNameIfNeeded(this, displayName, tagLayout)
                    }
                }
            }
        } catch (e: Exception) {
            SentryHelper.onEvent("GAME_DETAIL_SUBTRACT_GAME_NAME_ERROR", "exception_digest", e.localizedMessage)
        }
    }

    private fun calculateTextCountByWidth(textView: TextView, width: Int): Int {
        val textPaintWidth = textView.paint.measureText(textView.text.toString())
        val textWidth = textPaintWidth / textView.text.length
        return (width / textWidth).toInt()
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        mOrientationUtils = OrientationUtils(requireActivity(), mVideoBinding.player)
        mOrientationUtils?.isEnable = false
        setListener()

        // toolbar 消费 fitsSystemWindows 避免在 collapsingToolbar 下面出现多出来的 padding
        // [https://stackoverflow.com/questions/48137666/viewgroup-inside-collapsingtoolbarlayout-show-extra-bottom-padding-when-set-fits]
        ViewCompat.setOnApplyWindowInsetsListener(mBodyBinding.gamedetailAppbar) { _, insets ->
            (mBodyBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop
            insets.consumeSystemWindowInsets()
        }

        mBodyBinding.toolbar.setNavigationOnClickListener { requireActivity().finish() }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(bean: EBScroll) {
        if (mGameEntity?.id == bean.id) {
            mBodyBinding.gamedetailVp.currentItem = 0
            mBodyBinding.gamedetailAppbar.setExpanded(false, false)
        }
    }

    private fun observeData() {
        mViewModel.gameLiveData.observeNonNull(this) { gameResource ->
            if (gameResource.status == Status.SUCCESS) {
                mViewModel.logHistory(gameResource.data!!)
                mGameEntity = gameResource.data
                controlInstallHint()
                // 添加启动弹窗的相关信息
                if (mEntrance.contains(EntranceConsts.ENTRANCE_WELCOME) && mEntrance.countOccurrences("+") <= 1) {
                    mGameEntity?.setWelcomeDialogInfoIfAvailable()
                }
                NewFlatLogUtils.logGameDetailEnter(
                    mGameEntity?.name ?: "",
                    mGameEntity?.id ?: "",
                    mGameEntity?.shouldUseMirrorInfo() ?: false
                )
            } else if (gameResource.status == Status.ERROR) {
                loadErrorControl(gameResource.exception)
            }
        }

        mViewModel.gameDetailLiveData.observeNonNull(this) { detailResource ->
            if (detailResource.status == Status.SUCCESS) {
                val data = detailResource.data ?: return@observeNonNull

                DataLogUtils.uploadGameLog(context, mGameEntity!!.id, mGameEntity!!.name, mEntrance)

                SensorsBridge.trackEvent(
                    "GameDetailPageShow",
                    "game_id", mGameEntity?.id ?: "",
                    "game_name", mGameEntity?.name ?: "",
                    "download_status", mGameEntity?.downloadStatusChinese ?: "",
                    "cloud_save_tab_status", if (data.showArchive) "开启" else "关闭",
                    "game_type", mGameEntity?.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
                )

                mNewGameDetailEntity = data

                showAlertDialogIfNeeded(data)

                initViewPage(data)

                if (data.isShowContentCard(mGameEntity)) {
                    initGameContentCard(data.contentCard)
                }

                updateGameDetailTopArea()

                val viewHolder = detailViewHolder
                DetailDownloadUtils.detailInitDownload(viewHolder, true)

                mDestinationTab =
                    getTabPositionFromTabType(arguments?.getString(EntranceConsts.KEY_TARGET, TAB_DESC) ?: TAB_DESC)

                // destinationTab 的优先级最高，关注和关联关注在它的后面
                if (mDestinationTab != -1) {
                    tabPerformClick(mDestinationTab)
                }

                if (mAutoDownload || mIsOpenPlatformWindow && mGameEntity!!.getApk().size > 1) {
                    viewHolder.mDownloadPb.performClick()
                    mAutoDownload = false
                }

                mVideoBinding.player.goneIf(!mViewModel.displayTopVideo)
                mVideoBinding.videoPlaceholder.goneIf(mViewModel.displayTopVideo)
                if (mViewModel.displayTopVideo) {
                    data.topVideo?.let { setUpTopVideo(it) }
                    updateToolbarStyle(isToolbarWhite = false)
                } else {
                    updateToolbarStyle(isToolbarWhite = true)
                }

                mBinding.errorToolbarContainer.visibility = View.GONE
                controlReserveBtn()
                showVModeIconAtBottomBarIfNeeded(data.smoothRelatedGame, mGameEntity!!)

                showConcernIconAtBottomBarIfAvailable()

                mSkeleton?.hide()
            } else if (detailResource.status == Status.ERROR) {
                loadErrorControl(detailResource.exception)
            }
        }

        mViewModel.unifiedGameDetailWithUserRelatedInfoForParentLiveData.observeNonNull(this) {
            mNewGameDetailEntity = it
            updateGameDetailTopArea(updateUserRelatedViewOnly = true)
        }

        mViewModel.concernLiveData.observeNonNull(this) { response ->
            if (response.isConcern) {
                if (response.isSuccess) {
                    MtaHelper.onEvent("游戏详情_新", "关注", mGameEntity!!.name)
                    DataCollectionUtils.uploadConcern(
                        context,
                        mGameEntity!!.name,
                        mGameEntity!!.id,
                        "关注"
                    )

                    updateConcernMenuIcon(isConcerned = true)
                    toast(R.string.concern_success)
                } else {
                    toast(R.string.concern_failure)
                }
            } else {
                if (response.isSuccess) {
                    DataCollectionUtils.uploadConcern(
                        context,
                        mGameEntity!!.name,
                        mGameEntity!!.id,
                        "取消关注"
                    )
                    MtaHelper.onEvent("游戏详情_新", "取消关注", mGameEntity!!.name)

                    updateConcernMenuIcon(isConcerned = false)
                } else {
                    toast(R.string.cancel_concern_failure)
                }
            }
        }

        mPackageViewModel.filterSameUpdateLiveData.observe(this) {
            updateDownloadCountHint(it)
        }

        mViewModel.bigEventLiveData.observeNonNull(this) {
            GameBigEventDialog.showGameBigEventDialog(
                requireContext(), mGameEntity?.name ?: "", mGameEntity?.id ?: "", it, mEntrance
            )
        }
        mViewModel.recommendPopupLiveData.observe(this) {
            initRecommendUI()
        }

        mViewModel.archiveStatusLiveData.observeNonNull(this) { hasNew ->
            if (hasNew && mTabTitleList.contains(getString(R.string.game_detail_cloud_archive))) {
                updateArchiveTabUI()
            }
        }

        mUserViewModel.loginObsUserinfo.observe(this, Observer {
            if (it != null && mGameEntity != null) {
                postDelayedRunnable({
                    controlReserveBtn()
                    DetailDownloadUtils.detailInitDownload(detailViewHolder, true)
                }, 100)
            }
        })
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun initViewPage(data: NewGameDetailEntity) {
        // 各个 tab 显示的顺序为：详情>云存档>评价>专区>论坛

        val scrollToLibao = arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO) ?: false
        var scrollToServer = arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_SERVER) ?: false

        // 内容卡片包含开服表时不跳转详情开服表
        if (scrollToServer) {
            data.contentCard.forEach {
                if (it.type == "func_server" && data.isShowContentCard(mGameEntity)) {
                    scrollToServer = false
                    contentCardClick.invoke(it)
                }
            }
        }

        if (scrollToLibao || scrollToServer) {
            mBodyBinding.gamedetailAppbar.setExpanded(false, true)
        }

        val bundle = Bundle()
        bundle.putParcelable(GameEntity.TAG, mGameEntity)
        bundle.putString(EntranceConsts.KEY_ENTRANCE, mEntrance)
        bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO, scrollToLibao)
        bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_SERVER, scrollToServer)
        bundle.putBoolean(
            EntranceConsts.KEY_SCROLL_TO_LIBAO,
            arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO) ?: false
        )
        bundle.putBoolean(
            EntranceConsts.KEY_OPEN_VIDEO_STREAMING,
            arguments?.getBoolean(EntranceConsts.KEY_OPEN_VIDEO_STREAMING) ?: false
        )
        mFragmentsList.clear()
        mTabTitleList.clear()

        val tag = "android:switcher:${mBodyBinding.gamedetailVp.id}:"
        val descFragment = childFragmentManager.findFragmentByTag("${tag}$TAB_DESC") ?: DescFragment()
        descFragment.arguments = bundle
        mFragmentsList.add(descFragment)
        mTabTitleList.add(getString(R.string.game_detail_desc))
        mTabTypeList.add(TAB_DESC)

        if (data.showArchive) {
            val cloudArchiveFragment =
                childFragmentManager.findFragmentByTag("${tag}${TAB_ARCHIVE}") ?: CloudArchiveFragment()
            bundle.putParcelable(EntranceConsts.KEY_GAME, mGameEntity ?: GameEntity())
            bundle.putString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL, data.archiveTab.configUrl)
            cloudArchiveFragment.arguments = bundle
            mFragmentsList.add(cloudArchiveFragment)
            mTabTitleList.add(getString(R.string.game_detail_cloud_archive))
            mTabTypeList.add(TAB_ARCHIVE)

            NewFlatLogUtils.logCloudArchiveGameDetailTabRelated(
                "cloud_save_tab_show",
                mGameEntity?.id ?: "",
                mGameEntity?.name ?: ""
            )
        }

        if (data.showComment) {
            val ratingFragment = childFragmentManager.findFragmentByTag("${tag}${TAB_RATING}") ?: RatingFragment()
            bundle.putBoolean(EntranceConsts.KEY_SKIP_GAME_COMMENT, mSkipGameComment)
            bundle.putBoolean(EntranceConsts.KEY_DIRECT_COMMENT, data.directComment)
            ratingFragment.arguments = bundle
            mFragmentsList.add(ratingFragment)
            mTabTitleList.add(getString(R.string.game_detail_comment))
            mTabTypeList.add(TAB_RATING)
        }

        data.zone?.let {
            data.contentCard.forEach { contentCard ->
                if (contentCard.type == "func_zone" && data.isShowContentCard(mGameEntity)) return@let
            }
            if (it.style != "default" && data.bbsTab != null && mGameEntity?.shouldUseMirrorInfo() == false) {
                mFragmentsList.add(Fragment())
            } else if (it.style == "link") {
                //显示web页面
                val webFragment = childFragmentManager.findFragmentByTag("${tag}${TAB_TRENDS}") ?: WebFragment()
                val webBundle = Bundle()
                webBundle.putString(EntranceConsts.KEY_ENTRANCE, "游戏专区")
                webBundle.putString(EntranceConsts.KEY_URL, it.link)
                webBundle.putBoolean(WebFragment.KEY_OPEN_NATIVE_PAGE, true)
                webFragment.arguments = webBundle
                mFragmentsList.add(webFragment)
            } else {
                val fuliFragment = childFragmentManager.findFragmentByTag("${tag}${TAB_TRENDS}") ?: FuLiFragment()
                fuliFragment.arguments = bundle
                mFragmentsList.add(fuliFragment)
            }
            if (!TextUtils.isEmpty(it.customName)) {
                mTabTitleList.add(it.customName)
            } else {
                mTabTitleList.add(getString(R.string.game_detail_dongtai))
            }
            mTabTypeList.add(TAB_TRENDS)
        }

        var isShowBbs = true
        if (data.bbsTab != null) {
            data.contentCard.forEach { contentCard ->
                if (data.contentCard.size > 1 && contentCard.type == "func_bbs") {
                    isShowBbs = false
                    return@forEach
                }
            }
            if (isShowBbs && mGameEntity?.shouldUseMirrorInfo() == false) {
                mFragmentsList.add(Fragment())
                mTabTitleList.add(getString(R.string.game_detail_bbs))
                mTabTypeList.add(TAB_BBS)
            }
        }

        mBodyBinding.gamedetailTabbar.goneIf(mTabTitleList.size == 1)
        mBodyBinding.toolbarGapView.goneIf(mTabTitleList.size == 1)

        mBodyBinding.run {
            gamedetailVp.adapter =
                FragmentAdapter(childFragmentManager, mFragmentsList, mTabTitleList)
            gamedetailVp.doOnPageSelected {
                logTabClick(it)
            }
            gamedetailVp.currentItem = getTabPositionFromTabType(TAB_DESC)

            mBodyBinding.tabLayout.setupWithViewPager(gamedetailVp)
            mBodyBinding.tabIndicator.setupWithTabLayout(mBodyBinding.tabLayout)
            mBodyBinding.tabIndicator.setupWithViewPager(gamedetailVp)

            for (i in 0 until mBodyBinding.tabLayout.tabCount) {
                val tab = mBodyBinding.tabLayout.getTabAt(i) ?: continue
                val tabTitle = if (tab.text != null) tab.text.toString() else ""
                if (data.showArchive && i == getTabPositionFromTabType(TAB_ARCHIVE)) {
                    tab.customView = getArchiveTabView(tabTitle)
                    tab.view.run {
                        clipChildren = false
                        setPadding(0, 0, 0, 0)
                    }
                    (tab.view.parent as? ViewGroup)?.run {
                        clipChildren = false
                    }
                } else {
                    tab.customView = BaseFragment_TabLayout.createDefaultTabCustomView(requireContext(), tabTitle)
                }
                tab.view.setOnTouchListener { _, event ->
                    if (event.action == MotionEvent.ACTION_DOWN) {
                        handleTabTouchEvent(tabTitle)
                    }
                    return@setOnTouchListener false
                }
            }

            BaseFragment_TabLayout.initTabStyle(mBodyBinding.tabLayout, gamedetailVp.currentItem)
            updateToolbarStyle(gamedetailThumbSmall.visibility == View.VISIBLE)
        }
    }

    private fun showAlertDialogIfNeeded(detailEntity: NewGameDetailEntity) {
        if (detailEntity.detailDialogs.isEmpty()) return
        val dialog = retrieveAvailableDialog(detailEntity.detailDialogs)
        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 + mGameEntity?.id,
                    0
                ) != dayOfMonth.toLong()
            ) {
                SPUtils.setLong(SP_OPENED_DIALOG_TIME_PREFIX + mGameEntity?.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) {
        DialogHelper.showDialogWithHtmlContent(
            requireContext(),
            dialog.title,
            dialog.content,
            dialog.confirmButton.text.toString(),
            dialog.closeButtonText,
            {
                dialog.confirmButton.text = dialog.confirmButton.linkText
                DirectUtils.directToLinkPage(requireContext(), dialog.confirmButton, mEntrance, "")
            }
        )
    }

    private fun loadErrorControl(exception: HttpException?) {
        mBinding.errorToolbarContainer.visibility = View.VISIBLE
        mBinding.errorReuseToolbar.normalToolbar.setNavigationOnClickListener { requireActivity().finish() }
        mBodyBinding.gamedetailAppbar.visibility = View.GONE

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

        mSkeleton?.hide()
    }

    private fun updateGameDetailTopArea(updateUserRelatedViewOnly: Boolean = false) {
        if (updateUserRelatedViewOnly) {
            updateConcernMenuIcon(mNewGameDetailEntity!!.me.isGameConcerned)
            return
        }

        mBinding.reuseLoading.reuseLlLoading.visibility = View.GONE
        mBodyBinding.gamedetailAppbar.visibility = View.VISIBLE

        if (mNewGameDetailEntity!!.showComment) {
            if (mSkipGameComment) {
                tabPerformClick(getTabPositionFromTabType(TAB_RATING))
                mBodyBinding.gamedetailAppbar.setExpanded(false)
                mSkipGameComment = false
            }
        }

        updateConcernMenuIcon(mNewGameDetailEntity!!.me.isGameConcerned)
        mBaseHandler.postDelayed({
            mGameEntity?.gameType = mNewGameDetailEntity?.tagStyle?.joinToString("-") { it.name } ?: ""
            mBodyBinding.gamedetailGametag.setTags(mNewGameDetailEntity?.tagStyle!!)
        }, 5)
        mBodyBinding.gamedetailGametag.onClickListener = object : FlexLinearLayout.OnItemClickListener {
            override fun onMoreClickListener() {
                if (!isVisible) return
                MtaHelper.onEvent("游戏详情_新", "标签展开", mViewModel.game?.name ?: "")
                GameTagsDialog.showGameTagsDialog(
                    requireActivity(), mNewGameDetailEntity?.tagStyle!!, mGameEntity?.id
                        ?: "", mGameEntity?.name ?: ""
                )
            }

            override fun onItemClickListener(tag: TagStyleEntity) {
                NewLogUtils.logGameDetailTagClick(
                    mGameEntity?.id ?: "",
                    mGameEntity?.name ?: "",
                    tag.id,
                    tag.name,
                    tag.isTop
                )
                MtaHelper.onEvent("游戏详情_新", "点击标签", mViewModel.game?.name ?: "")
                requireContext().startActivity(
                    TagsActivity.getIntent(requireContext(), tag.name, tag.name, mEntrance, "游戏介绍")
                )
            }
        }
        val recommendAge = mNewGameDetailEntity?.recommendAge
        mBodyBinding.recommendAgeIv.goneIf(recommendAge.isNullOrEmpty())
        if (!recommendAge.isNullOrEmpty()) {
            val recommendAgeRes = when (recommendAge) {
                "8+" -> R.drawable.ic_recommend_age8
                "12+" -> R.drawable.ic_recommend_age12
                "16+" -> R.drawable.ic_recommend_age16
                else -> -1
            }
            if (recommendAgeRes > 0) {
                mBodyBinding.recommendAgeIv.setImageDrawable(recommendAgeRes.toDrawable())
            }
        }
        mBodyBinding.ratingScoreContainer.goneIf(!mNewGameDetailEntity!!.showComment)
        if (mGameEntity?.commentCount ?: 0 > 3) {
            mBodyBinding.ratingScoreAverage.textSize = 18f
            mBodyBinding.ratingScoreAverage.text = if (mGameEntity?.star == 10F) "10" else mGameEntity?.star.toString()
        } else {
            mBodyBinding.ratingScoreAverage.textSize = 8f
            mBodyBinding.ratingScoreAverage.text = "评分过少"
        }

        mNewGameDetailEntity?.certificateTag?.let { screenshot ->
            mBodyBinding.realnameHintTv.visibility = View.VISIBLE
            if (!TextUtils.isEmpty(screenshot.screenshot)) {
                mBodyBinding.realnameHintTv.setOnClickListener {
                    val intent = ImageViewerActivity.getIntent(
                        requireContext(),
                        arrayListOf(screenshot.screenshot),
                        0,
                        "游戏详情"
                    )
                    startActivity(intent)
                }
            }
        }

        mBodyBinding.gamedetailTvName.text = mGameEntity!!.name
        if (mGameEntity!!.subtitle.isNotEmpty() || mGameEntity!!.advanceDownload) {
            initGameSubtitle(
                mBodyBinding.gamedetailTvName,
                mGameEntity!!.subtitle,
                mGameEntity!!.subtitleStyle,
                mGameEntity!!.advanceDownload
            )
        }
        mBodyBinding.gamedetailTvName.isSelected = true
        val ranking = mNewGameDetailEntity!!.ranking
        val shouldShowRank =
            (ranking != null && (mGameEntity?.iconFloat == null || mGameEntity?.iconFloat?.bottomText.isNullOrEmpty())) || (ranking != null && ranking.no.toInt() <= 10 && mGameEntity?.iconFloat != null && !mGameEntity?.iconFloat?.bottomText.isNullOrEmpty())
        if (ranking != null && shouldShowRank) {
            mBodyBinding.gameDetailRankLl.visibility = View.VISIBLE
            mBodyBinding.gameDetailRankTv.text = "${ranking.columnName}第${ranking.no}名"
            mBodyBinding.gameDetailRankTv.isSelected = true
            mBodyBinding.gameDetailRankLl.setOnClickListener {
                MtaHelper.onEvent("游戏详情_新", "点击榜单", "${mViewModel.game?.name}+${ranking.columnName}")
                DirectUtils.directToColumnCollection(
                    requireContext(),
                    ranking.collectionId,
                    entrance = mEntrance,
                    columnName = ranking.columnName
                )
            }
        }

        BindingAdapters.setGame(mBodyBinding.gamedetailIvThumb, mGameEntity?.apply {
            if (shouldShowRank && iconFloat != null) iconFloat!!.bottomText = ""
        })
        BindingAdapters.setGame(mBodyBinding.gamedetailThumbSmall, mGameEntity)

        mNewGameDetailEntity?.event?.let {
            mBodyBinding.gameBigEvent.visibility = View.VISIBLE
            if (it.highLight) {
                mBodyBinding.gameBigEvent.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_2A85FB))
                mBodyBinding.gameBigEvent.background =
                    ContextCompat.getDrawable(requireContext(), R.drawable.bg_game_big_event_light)
                mBodyBinding.gameBigEvent.setCompoundDrawablesWithIntrinsicBounds(
                    ContextCompat.getDrawable(requireContext(), R.drawable.ic_game_detail_big_event), null,
                    ContextCompat.getDrawable(requireContext(), R.drawable.ic_game_detail_big_event_arrow), null
                )
                var eventStr =
                    "${TimeUtils.getFormatTime(it.time, "MM-dd")}${TimeUtils.getDayString(it.time)}：${it.content}"
                if (eventStr.contains("\n")) eventStr = eventStr.substring(0, eventStr.indexOf("\n"))
                mBodyBinding.gameBigEvent.text = eventStr
            } else {
                mBodyBinding.gameBigEvent.setTextColor(
                    ContextCompat.getColor(
                        requireContext(),
                        R.color.text_subtitleDesc
                    )
                )
                mBodyBinding.gameBigEvent.background =
                    ContextCompat.getDrawable(requireContext(), R.drawable.bg_game_big_event)
                mBodyBinding.gameBigEvent.setCompoundDrawablesWithIntrinsicBounds(
                    ContextCompat.getDrawable(requireContext(), R.drawable.ic_game_detail_big_event_gray), null,
                    ContextCompat.getDrawable(requireContext(), R.drawable.ic_game_detail_big_event_arrow_gray), null
                )
                var eventStr = if (TimeUtils.getBeforeDays(it.time) <= 15) "${
                    TimeUtils.getFormatTime(it.time, "MM-dd")
                }${TimeUtils.getDayString(it.time)}：${it.content}" else it.content
                if (eventStr.contains("\n")) eventStr = eventStr.substring(0, eventStr.indexOf("\n"))
                mBodyBinding.gameBigEvent.text = eventStr
            }
            mBodyBinding.gameBigEvent.setOnClickListener {
                MtaHelper.onEvent("游戏详情_新", "游戏大事件", mViewModel.game?.name ?: "")
                NewLogUtils.logGameDetailMajorEventClick(mViewModel.game?.name ?: "", mViewModel.game?.id ?: "")
                mViewModel.getBigEvent()
            }
        }
    }

    private fun initGameContentCard(linkEntityList: ArrayList<ContentCardEntity>) {

        if (mGameEntity?.shouldUseMirrorInfo() == true) {
            val funcBbs = linkEntityList.find { it.type == "func_bbs" }
            val funcServer = linkEntityList.find { it.type == "func_server" }
            // 镜像游戏不显示链接类型为“功能类-论坛”的内容卡片
            funcBbs?.let {
                linkEntityList.remove(it)
            }
            // 镜像游戏显示链接类型为“功能类-开服”的内容卡片需判断calendar是否有数据
            if (funcServer != null && funcServer.server?.calendar.isNullOrEmpty()) {
                linkEntityList.remove(funcServer)
            }
        }
        mBodyBinding.toolbarGapView.visibility = View.GONE
        mBodyBinding.contentCardContainer.removeAllViews()
        mBodyBinding.contentCardContainer.visibility = View.VISIBLE
        if (linkEntityList.size >= 3) {
            linkEntityList.safelyGetInRelease(0)?.let {
                mBodyBinding.contentCardContainer.addView(
                    getLargeContentCardView(it, true, position = 1),
                    LinearLayout.LayoutParams(0, 56F.dip2px(), 2F)
                )
            }
            linkEntityList.safelyGetInRelease(1)?.let {
                mBodyBinding.contentCardContainer.addView(
                    getSmallContentCardView(it, position = 2),
                    LinearLayout.LayoutParams(0, 56F.dip2px(), 1F)
                )
            }
            linkEntityList.safelyGetInRelease(2)?.let {
                mBodyBinding.contentCardContainer.addView(
                    getSmallContentCardView(it, true, position = 3),
                    LinearLayout.LayoutParams(0, 56F.dip2px(), 1F)
                )
            }
        } else if (linkEntityList.size == 2) {
            linkEntityList.safelyGetInRelease(0)?.let {
                mBodyBinding.contentCardContainer.addView(
                    getLargeContentCardView(it, position = 1),
                    LinearLayout.LayoutParams(0, 56F.dip2px(), 1F)
                )
            }
            linkEntityList.safelyGetInRelease(1)?.let {
                mBodyBinding.contentCardContainer.addView(
                    getLargeContentCardView(it, isLastView = true, position = 2),
                    LinearLayout.LayoutParams(0, 56F.dip2px(), 1F)
                )
            }
        }
    }

    private fun getLargeContentCardView(
        contentCardEntity: ContentCardEntity,
        isHighlightBg: Boolean = false,
        isLastView: Boolean = false,
        position: Int
    ) = LayoutGameDetailContentCardLargeBinding.inflate(layoutInflater).apply {
        when {
            isHighlightBg && !isLastView -> root.background =
                R.drawable.bg_content_card_large_primary.toDrawable(requireContext())

            !isHighlightBg && !isLastView -> root.background =
                R.drawable.bg_content_card_large.toDrawable(requireContext())

            !isHighlightBg && isLastView -> root.background =
                R.drawable.bg_content_card_large_right.toDrawable(requireContext())
        }
        root.setPadding(
            if (isLastView) 20F.dip2px() else 12F.dip2px(),
            0,
            if (isLastView) 8F.dip2px() else 12F.dip2px(),
            0
        )
        titleTv.text = contentCardEntity.title
        ImageUtils.display(iconIv, contentCardEntity.icon)
        if (contentCardEntity.des.isNotEmpty() || contentCardEntity.type == "func_libao") {
            contentTv.visibility = View.VISIBLE
            contentVp.visibility = View.GONE
            contentTv.text =
                if (contentCardEntity.type == "func_libao" && contentCardEntity.des.isEmpty()) "${contentCardEntity.libao?.total}个游戏礼包" else contentCardEntity.des
            contentTv.setTextColor(
                if (isHighlightBg) R.color.text_subtitle.toColor(requireContext()) else R.color.text_subtitleDesc.toColor(
                    requireContext()
                )
            )
        } else if (contentCardEntity.type == "func_server") {
            contentTv.visibility = View.GONE
            contentVp.visibility = View.VISIBLE
            if (contentCardEntity.type == "func_server") mContentCardServerVp = contentVp
            contentVp.run {
                isUserInputEnabled = false
                orientation = ViewPager2.ORIENTATION_VERTICAL
                adapter = GameDetailContentCardContentAdapter(requireContext(), contentCardEntity, isHighlightBg)
                if (contentCardEntity.type == "func_server") {
                    val nowTime = System.currentTimeMillis()
                    var timeDiff = 0L
                    var closestIndex = 0
                    contentCardEntity.server!!.calendar.forEachIndexed { index, serverCalendarEntity ->
                        val diff = abs(nowTime - serverCalendarEntity.getTime() * 1000L)
                        if (diff < timeDiff || index == 0) {
                            timeDiff = diff
                            closestIndex = index
                        }
                    }
                    setCurrentItem(closestIndex, false)
                    if (contentCardEntity.server!!.calendar.size > 1) {
                        startAutoPlay(mServerLooperKey)
                    }
                }
            }
        }
        redDotTv.goneIf(!((contentCardEntity.type == "func_server" && contentCardEntity.server?.total != 0) || contentCardEntity.type == "func_libao"))
        if ((contentCardEntity.type == "func_server") && (contentCardEntity.server?.calendar?.isNotEmpty() == true)) redDotTv.text =
            contentCardEntity.server?.total.toString()
        if ((contentCardEntity.type == "func_libao") && (contentCardEntity.libao != null)) redDotTv.text =
            contentCardEntity.libao?.total.toString()
        root.setOnClickListener {
            contentCardClick.invoke(contentCardEntity)
        }
        ExposureManager.log(
            ExposureEvent.createEvent(
                GameEntity(sequence = position),
                listOf(
                    ExposureSource("游戏详情", mGameEntity?.id ?: ""),
                    ExposureSource("内容卡片", contentCardEntity.id)
                )
            )
        )
    }.root

    private fun getSmallContentCardView(
        contentCardEntity: ContentCardEntity,
        isLastView: Boolean = false,
        position: Int
    ) = LayoutGameDetailContentCardSmallBinding.inflate(layoutInflater).apply {
        root.background =
            if (isLastView) R.drawable.bg_content_card_small_right.toDrawable(requireContext()) else R.drawable.bg_content_card_small.toDrawable(
                requireContext()
            )
        titleTv.text = contentCardEntity.title
        ImageUtils.display(iconIv, contentCardEntity.icon)
        redDotTv.goneIf(!((contentCardEntity.type == "func_server" && contentCardEntity.server?.total != 0) || contentCardEntity.type == "func_libao"))
        redDotTv.layoutParams = (redDotTv.layoutParams as ViewGroup.MarginLayoutParams).apply {
            setMargins(
                0,
                8F.dip2px(),
                if (isLastView) 8F.dip2px() else 12F.dip2px(),
                0
            )
        }
        if ((contentCardEntity.type == "func_server") && (contentCardEntity.server?.calendar?.isNotEmpty() == true)) redDotTv.text =
            contentCardEntity.server?.total.toString()
        if ((contentCardEntity.type == "func_libao") && (contentCardEntity.libao != null)) redDotTv.text =
            contentCardEntity.libao?.total.toString()
        root.setOnClickListener {
            contentCardClick.invoke(contentCardEntity)
        }
        ExposureManager.log(
            ExposureEvent.createEvent(
                GameEntity(sequence = position),
                listOf(
                    ExposureSource("游戏详情", mGameEntity?.id ?: ""),
                    ExposureSource("内容卡片", contentCardEntity.id)
                )
            )
        )
    }.root

    private fun scrollToNextContent(viewPager: ViewPager2? = null) {
        viewPager?.run {
            val pxToDrag: Int = height
            val animator = ValueAnimator.ofInt(0, pxToDrag)
            var previousValue = 0
            animator.addUpdateListener { valueAnimator ->
                val currentValue = valueAnimator.animatedValue as Int
                val currentPxToDrag = (currentValue - previousValue).toFloat()
                fakeDragBy(-currentPxToDrag)
                previousValue = currentValue
            }
            animator.addListener(object : Animator.AnimatorListener {
                override fun onAnimationStart(animation: Animator) {
                    beginFakeDrag()
                }

                override fun onAnimationEnd(animation: Animator) {
                    endFakeDrag()
                }

                override fun onAnimationCancel(animation: Animator) {}
                override fun onAnimationRepeat(animation: Animator) {}
            })
            animator.interpolator = AccelerateDecelerateInterpolator()
            animator.duration = 1000
            animator.start()
        }
    }

    private fun startAutoPlay(key: Int) {
        mLooperHandle.removeMessages(key)
        mLooperHandle.sendEmptyMessageDelayed(key, CONTENT_CARD_LOOP_TIME)
    }

    private fun setUpTopVideo(topVideo: Video) {
        GSYVideoOptionBuilder()
            .setIsTouchWigetFull(false)
            .setIsTouchWiget(false)
            .setRotateViewAuto(false)
            .setShowFullAnimation(false)
            .setSeekRatio(1f)
            .setUrl(topVideo.url)
            .setCacheWithPlay(true)
            .setShowPauseCover(true)
            .setReleaseWhenLossAudio(false)
            .setVideoAllCallBack(object : GSYSampleCallBack() {
                override fun onQuitFullscreen(url: String?, vararg objects: Any) {
                    mOrientationUtils?.backToProtVideo()
                    mVideoBinding.player.uploadVideoStreamingPlaying("退出全屏")
                }
            })
            .build(mVideoBinding.player)

        mVideoBinding.player.gameName = mGameEntity?.name ?: ""
        mVideoBinding.player.viewModel = mViewModel
        mVideoBinding.player.video = topVideo
        mVideoBinding.player.updateThumb(topVideo.poster)

        //val trafficVideo = PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SettingsFragment.TRAFFIC_VIDEO_SP_KEY, false)
        val videoOption = SPUtils.getString(
            Constants.SP_HOME_OR_DETAIL_VIDEO_OPTION,
            Constants.VIDEO_OPTION_WIFI
        )
            ?: Constants.VIDEO_OPTION_WIFI
        when (videoOption) {
            Constants.VIDEO_OPTION_ALL -> {
                mVideoBinding.player.startPlayLogic(isAutoPlay = true)
            }

            Constants.VIDEO_OPTION_WIFI -> {
                if (NetworkUtils.isWifiConnected(requireContext()) /*|| !trafficVideo*/) {
                    if (mViewModel.isTopVideoPartlyCached(topVideo.url)) {
                        mVideoBinding.player.startPlayLogic(isAutoPlay = true)
                    } else {
                        // 未有缓存时，为避免影响页面加载，延迟自动播放视频
                        postDelayedRunnable({
                            if (activity != null && activity?.isFinishing != true) {
                                mVideoBinding.player.startPlayLogic(isAutoPlay = true)
                            }
                        }, INITIAL_DELAY)
                    }
                }
            }

            else -> {
            }
        }

        mVideoBinding.player.fullscreenButton.setOnClickListener {
            val horizontalVideoView =
                mVideoBinding.player.startWindowFullscreen(requireContext(), true, true) as? TopVideoView
            if (horizontalVideoView == null) {
                toastInInternalRelease("全屏失败，请向技术人员提供具体的操作步骤")
                return@setOnClickListener
            }
            mOrientationUtils?.resolveByClick()
            horizontalVideoView.uuid = mVideoBinding.player.uuid
            horizontalVideoView.viewModel = mViewModel
            horizontalVideoView.video = topVideo
            horizontalVideoView.updateThumb(topVideo.poster)
            horizontalVideoView.violenceUpdateMuteStatus()
            mVideoBinding.player.uploadVideoStreamingPlaying("开始播放")
            mVideoBinding.player.uploadVideoStreamingPlaying("点击全屏")
            MtaHelper.onEvent("游戏详情_顶部视频", "顶部视频-点击进入全屏", mVideoBinding.player.combinedTitleAndId)
        }

        mVideoBinding.player.observeVolume(this)
    }

    private fun updateToolbarStyle(isToolbarWhite: Boolean) {
        mBodyBinding.titleTv.setTextColor(
            ContextCompat.getColor(
                requireContext(),
                if (!mIsDarkModeOn && isToolbarWhite) R.color.black else R.color.white
            )
        )
        mBodyBinding.toolbar.setNavigationIcon(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.ic_bar_back else R.drawable.ic_bar_back_light)
        mBodyBinding.toolbar.post {
            if (context != null) {
                mBodyBinding.toolbar.setBackgroundColor(
                    if (isToolbarWhite) R.color.background_white.toColor(requireContext()) else R.color.transparent.toColor(
                        requireContext()
                    )
                )
            }
        }
        DisplayUtils.setStatusBarColor(
            requireActivity(),
            if (isToolbarWhite) R.color.background_white else R.color.transparent,
            true
        )
        updateConcernMenuIcon(mNewGameDetailEntity?.me?.isGameConcerned ?: false)
        mMoreMenuItem?.setIcon(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.ic_menu_gamedetail_more else R.drawable.ic_menu_gamedetail_more_light)
        mSearchMenuItem?.setIcon(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.ic_column_search else R.drawable.ic_column_search_light)
        mDownloadMenuIcon?.setImageResource(if (!mIsDarkModeOn && isToolbarWhite) R.drawable.toolbar_download else R.drawable.toolbar_download_light)
        DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn && isToolbarWhite)
    }

    override fun onTouchEvent(event: MotionEvent) {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> mIsTouchScreen = true
            MotionEvent.ACTION_UP -> mIsTouchScreen = false
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(reuse: EBReuse) {
        if (SKIP_DESC == reuse.type) {
            tabPerformClick(getTabPositionFromTabType(TAB_DESC))
        } else if (OPEN_APPBAR == reuse.type && !mIsTouchScreen) {
            mBodyBinding.gamedetailAppbar.setExpanded(true, true)
        } else if (SKIP_FULI == reuse.type) {
            tabPerformClick(getTabPositionFromTabType(TAB_TRENDS))
        } else if (SKIP_RATING == reuse.type) {
            tabPerformClick(getTabPositionFromTabType(TAB_RATING))
        } else if ("hideKaifuHint" == reuse.type) {
            mIsShowKaifuHint = false
            mBinding.gamedetailKaifuHint.visibility = View.GONE
        } else if ("showKaifuHint" == reuse.type) {
            mIsShowKaifuHint = true
            if (mCurVpPosition == getTabPositionFromTabType(TAB_TRENDS)) {
                mBinding.gamedetailKaifuHint.post { mBinding.gamedetailKaifuHint.visibility = View.VISIBLE }
            }
        } else if (CLOSE_APPBAR == reuse.type && !mIsTouchScreen) {
            mBodyBinding.gamedetailAppbar.setExpanded(false, true)
        } else if ("download" == reuse.type) {
            mDownloadBinding.detailProgressbar.performClick()
        }
    }

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

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

    // 关注事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(changed: EBConcernChanged) {
        if (mNewGameDetailEntity != null && mGameEntity != null && changed.isSingle && changed.gameId == mGameEntity!!.id) {
            mNewGameDetailEntity!!.me.isGameConcerned = changed.isConcern
            updateGameDetailTopArea()
        }
    }

    // 更新评分
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(data: EBStar) {
        if (data.commentCount > 3) {
            mBodyBinding.ratingScoreAverage.textSize = 18F
            mBodyBinding.ratingScoreAverage.text = if (data.star == 10F) "10" else data.star.toString()
        } else {
            mBodyBinding.ratingScoreAverage.textSize = 8F
            mBodyBinding.ratingScoreAverage.text = "评分过少"
        }
    }

    private fun setListener() {
        mBodyBinding.toolbar.setOnClickListener {
            scrollToTop()
        }
        mBinding.reuseNoConnection.root.setOnClickListener {
            mBinding.reuseLoading.reuseLlLoading.visibility = View.VISIBLE
            mBinding.reuseNoConnection.reuseNoConnection.visibility = View.GONE
            mBinding.errorToolbarContainer.visibility = View.GONE
            mSkeleton?.show()
            mViewModel.loadData()
        }
        mBinding.gamedetailKaifuHint.setOnClickListener {
            mBodyBinding.gamedetailAppbar.setExpanded(false, true)
            mIsScrollToKaiFu = true
        }
        mDownloadBinding.ivConcern.setOnClickListener {
            ifLogin("游戏详情-[关注]") {
                if (mNewGameDetailEntity != null && mNewGameDetailEntity!!.me.isGameConcerned) {
                    DialogHelper.showCancelDialog(requireContext(), {
                        mViewModel.concernCommand(false)
                    })
                } else {
                    mViewModel.concernCommand(true)
                }
            }
        }
        mDownloadBinding.tvConcern.setOnClickListener { mDownloadBinding.ivConcern.performClick() }
        mDownloadBinding.ivReserve.setOnClickListener {
            if (mGameEntity != null && SimulatorGameManager.isSimulatorGame(mGameEntity!!)) {
                startActivity(SimulatorGameActivity.getIntent(requireContext()))
                return@setOnClickListener
            }
            CheckLoginUtils.checkLogin(requireContext(), "游戏详情") {
                if (!ReservationRepository.thisGameHasBeenReserved(mGameEntity?.id ?: "")) {
                    ReservationHelper.reserve(
                        requireContext(),
                        mGameEntity?.id ?: "",
                        mGameEntity?.name ?: "",
                        getCallback()
                    )
                } else {
                    if ("download" == mGameEntity?.reserveStatus) {
                        ReservationHelper.showDeleteReservationDialog(
                            requireContext(),
                            object : EmptyCallback {
                                override fun onCallback() {
                                    ReservationHelper.deleteReservation(
                                        mGameEntity!!,
                                        object : EmptyCallback {
                                            override fun onCallback() {
                                                DetailDownloadUtils.detailInitDownload(detailViewHolder, false)
                                                showReserveBtn(isShowReserveBtn())
                                            }
                                        })
                                }
                            })
                    } else {
                        ReservationHelper.showCancelReservationDialog(
                            requireContext(),
                            object : EmptyCallback {
                                override fun onCallback() {
                                    ReservationHelper.cancelReservation(
                                        mGameEntity!!,
                                        object : EmptyCallback {
                                            override fun onCallback() {
                                                DetailDownloadUtils.detailInitDownload(detailViewHolder, false)
                                                showReserveBtn(isShowReserveBtn())
                                            }
                                        })
                                }
                            })
                    }
                }
            }
        }
        mDownloadBinding.tvReserve.setOnClickListener { mDownloadBinding.ivReserve.performClick() }
        mDownloadBinding.ivSwitch.setOnClickListener {
            val intent = ShellActivity.getIntent(requireContext(), ShellActivity.Type.SWITCH_INSTALL_METHOD, null)
            requireActivity().startActivity(intent)
        }
        mDownloadBinding.tvSwitch.setOnClickListener { mDownloadBinding.ivSwitch.performClick() }
        mBinding.popReserverGuide.closeIv.setOnClickListener {
            showReserveGuide(false)
        }
        mRecommendBinding.recommendCloseIv.setOnClickListener {
            hideRecommendView(true)
        }
    }

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

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

        val downloadMenuView = mBodyBinding.toolbar.menu.findItem(R.id.menu_download).actionView
        mDownloadCountHint = downloadMenuView?.findViewById(R.id.menu_download_count_hint)
    }

    private fun updateDownloadCountHint(updateList: List<GameUpdateEntity>?) {
        val count = DownloadManager.getInstance().getDownloadOrUpdateCount(updateList)
        val params = mDownloadCountHint?.layoutParams
        if (TextUtils.isEmpty(count)) {
            params?.width = DisplayUtils.dip2px(6f)
            params?.height = DisplayUtils.dip2px(6f)
        } else {
            params?.width = DisplayUtils.dip2px(12f)
            params?.height = DisplayUtils.dip2px(12f)
        }
        mDownloadCountHint?.layoutParams = params

        mDownloadCountHint?.goneIf(count == null)
        mDownloadCountHint?.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 && mGameEntity?.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 (mGameEntity != null && SimulatorGameManager.isSimulatorGame(mGameEntity!!)) {
            mDownloadBinding.ivReserve.visibility = View.VISIBLE
            mDownloadBinding.tvReserve.visibility = View.VISIBLE
            mDownloadBinding.tvReserve.text = "管理"
            mDownloadBinding.ivReserve.setImageResource(R.drawable.ic_gamedetail_simulator_manage)
            return
        }

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

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

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

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

    private fun pauseVideo() {
        if (mViewModel.displayTopVideo) {
            mVideoBinding.player.onVideoPause()
        }
    }

    private fun resumeVideo() {
        if (mViewModel.displayTopVideo) {
            mVideoBinding.player.onVideoResume()
        }
    }

    private fun releaseVideo() {
        if (mViewModel.displayTopVideo) {
            mVideoBinding.player.release()
            mVideoBinding.player.disposableTimer()
        }
    }

    private fun tabPerformClick(position: Int) {
        val trendsTabPosition = getTabPositionFromTabType(TAB_TRENDS)
        val bbsTabPosition = getTabPositionFromTabType(TAB_BBS)

        when (position) {
            trendsTabPosition -> {
                val zoneEntity = mNewGameDetailEntity?.zone
                if (!mTabTitleList.contains(getString(R.string.game_detail_dongtai))
                    && !mTabTitleList.contains(zoneEntity?.customName)
                ) {
                    performJumpContentCard("func_zone")
                } else {
                    mBodyBinding.gamedetailVp.currentItem = getTabPositionFromTabType(TAB_TRENDS)
                }
            }

            bbsTabPosition -> {
                if (!mTabTitleList.contains(getString(R.string.game_detail_bbs))) {
                    performJumpContentCard("func_bbs")
                } else {
                    mBodyBinding.gamedetailVp.currentItem = getTabPositionFromTabType(TAB_BBS)
                }
            }

            else -> {
                mBodyBinding.gamedetailVp.currentItem = position
            }
        }
    }

    private fun performJumpContentCard(type: String) {
        val entity = mNewGameDetailEntity?.contentCard?.find { it.type == type }
        if (mNewGameDetailEntity?.isShowContentCard(mGameEntity) == true
            && entity != null
        ) {
            contentCardClick(entity)
        }
    }

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

        val entrance = if (mEntrance.contains("论坛详情")) "论坛" else "游戏"
        mGameEntity?.run {
            when (mTabTypeList[position]) {
                TAB_DESC -> {
                    NewLogUtils.logGameDetailTabClick(name ?: "", id, "详情")
                }

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

                TAB_ARCHIVE -> {
                    NewFlatLogUtils.logCloudArchiveGameDetailTabRelated(
                        "cloud_save_tab_click",
                        mGameEntity?.id ?: "",
                        mGameEntity?.name ?: ""
                    )
                    SensorsBridge.trackEvent(
                        "CloudSaveTabSelected",
                        "game_id", mGameEntity?.id ?: "",
                        "game_name", mGameEntity?.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
                    )
                }

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

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

    /**
     * 获取 tab 的位置
     * @param tabType tab 类型
     * @return tab 的真实位置
     */
    private fun getTabPositionFromTabType(tabType: String): Int {
        return mTabTypeList.indexOf(tabType)
    }

    private fun handleTabTouchEvent(title: String) {
        if (title == mTabClickEvent.second && System.currentTimeMillis() - mTabClickEvent.first < 300) {
            val fragment = mFragmentsList[mBodyBinding.gamedetailVp.currentItem]
            if (fragment is IScrollable && fragment.isAdded) {
                fragment.scrollToTop()
            }
        } else {
            mTabClickEvent = Pair(System.currentTimeMillis(), title)
            // 部分手机触发了 touch 但是没有触发 viewpager 的变动，这里手动帮它一下
            when (title) {
                getString(R.string.game_detail_dongtai),
                getString(R.string.game_detail_comment),
                getString(R.string.game_detail_cloud_archive) -> {
                    mBodyBinding.gamedetailAppbar.setExpanded(false, true)
                    tabPerformClick(getTabPositionFromTabType(title))
                }

                else -> {
                    // do nothing
                }
            }
        }
    }

    private fun showBrowserInstallHintIfNeeded() {
        if (BrowserInstallHelper.shouldShowGameDetailUseBrowserToInstallHint()) {
            mDownloadBinding.browserInstallHintContainer.visibility = View.VISIBLE
            mDownloadBinding.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.toUpperCase(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 =
                    "关闭后“切换安装方式”入口将显示在左下角，您也可以前往“我的光环-设置-切换安装方式”进行设置"
            }

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

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

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

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

    private fun initRecommendUI() {
        val recommendPopupList = mViewModel.recommendPopupLiveData.value
        mRecommendPopupEntity = RecommendPopupHelper.getRecommendPopup(mViewModel.game, recommendPopupList) ?: return
        val popupDetail = mRecommendPopupEntity!!.popupDetail
        mRecommendBinding.recommendText.text = popupDetail.text
        if (popupDetail.images.isNotEmpty()) {
            ImageUtils.display(mRecommendBinding.recommendImage, popupDetail.images[0])
            mRecommendBinding.recommendImage.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
                override fun loaded() {
                    mRecommendBinding.recommendImage.post {
                        mRecommendBinding.recommendImage.layoutParams.apply {
                            width = 68f.dip2px()
                            height = (width / mRecommendBinding.recommendImage.aspectRatio).toInt()
                            mRecommendBinding.recommendImage.layoutParams = this
                        }
                    }
                }
            })
        } else {
            mRecommendBinding.recommendImage.visibility = View.GONE
            (mRecommendBinding.recommendText.layoutParams as ConstraintLayout.LayoutParams).apply {
                leftMargin = 16f.dip2px()
                mRecommendBinding.recommendText.layoutParams = this
            }
            mRecommendBinding.recommendText.maxWidth = 150f.dip2px()
        }
        mRecommendBinding.recommendLinkTv.text = popupDetail.link?.title
        mRecommendBinding.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", mRecommendPopupEntity?.id, mViewModel.game?.id
                        ?: "", mViewModel.game?.name ?: "", it.type, it.text, "", ""
                )
            }
        }
    }

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

    private fun hideRecommendView(isManuallyClose: Boolean = false) {
        mRecommendBinding.recommendView.post {
            if (mIsRecommendViewShow) {
                val width = mRecommendBinding.recommendView.measuredWidth.toFloat()
                mRecommendBinding.recommendView.animate().x(-width).setDuration(500).start()
                mIsRecommendViewShow = false
                mRecommendDisposable?.dispose()
                mRecommendDisposable = null
                if (isManuallyClose) {
                    LogUtils.uploadRecommendPopup(
                        "recommend_pop_close", mRecommendPopupEntity?.id, mViewModel.game?.id
                            ?: "", mViewModel.game?.name ?: "", "", "", "", ""
                    )
                }
            }
        }
    }

    private fun getArchiveTabView(title: String) =
        ArchiveTabItemBinding.inflate(layoutInflater).apply {
            val hasEnterArchiveGameDetail = SPUtils.getBoolean(getHasEnterArchiveGameDetailSPKey(mGameEntity?.id ?: ""))
            val hasNewArchive = mViewModel.archiveStatusLiveData.value ?: false
            tabTitle.text = title
            newIv.goneIf(hasEnterArchiveGameDetail && !hasNewArchive)
            if (!hasEnterArchiveGameDetail) {
                SPUtils.setBoolean(getHasEnterArchiveGameDetailSPKey(mGameEntity?.id ?: ""), true)
            }
        }.root

    private fun updateArchiveTabUI() {
        mBodyBinding.tabLayout.run {
            val archivePosition = getTabPositionFromTabType(TAB_ARCHIVE)
            getTabAt(archivePosition)?.customView?.findViewById<ImageView>(R.id.newIv)?.visibility = View.VISIBLE
        }
    }

    private fun getHasEnterArchiveGameDetailSPKey(gameId: String) = SP_HAS_ENTER_ARCHIVE_GAME_DETAIL_PREFIX + gameId

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

    override fun onBackPressed(): Boolean {
        mOrientationUtils?.backToProtVideo()

        val trendsTabPosition = getTabPositionFromTabType(TAB_TRENDS)

        if (mBodyBinding.gamedetailVp.currentItem == trendsTabPosition
            && mFragmentsList[trendsTabPosition] is WebFragment
            && mFragmentsList[trendsTabPosition].isAdded
        ) {
            return (mFragmentsList[trendsTabPosition] as WebFragment).onBackPressed()
        }

        if (CustomManager.backFromWindowFull(requireActivity(), mVideoBinding.player.getKey())) {
            return true
        }

        return super.onBackPressed()
    }

    override fun onResume() {
        super.onResume()
        if (!mIsPauseTopVideo && mIsPlayingWhenPause) {
            resumeVideo()
        }
        if (mGameEntity != null && (mGameEntity!!.getApk().size == 1 || mGameEntity!!.isReservable)) {
            DetailDownloadUtils.detailInitDownload(detailViewHolder, true)
        }

        showBrowserInstallHintIfNeeded()

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

    override fun onPause() {
        super.onPause()
        if (mViewModel.displayTopVideo) {
            mVideoBinding.player.postDelayed({
                mVideoBinding.player.showFullPauseBitmap()
            }, 50)
            mIsPlayingWhenPause = CustomManager.getCustomManager(mVideoBinding.player.getKey()).isPlaying
            pauseVideo()
            val currentPosition = mVideoBinding.player.getCurrentPosition()
            val topVideo = mNewGameDetailEntity?.topVideo
            if (topVideo != null) {
                ScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(topVideo.url), currentPosition)
            }
        }
        hideRecommendView()
    }

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

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

    private fun getCallback(): EmptyCallback {
        return EmptyCallback {
            LogUtils.logReservation(mGameEntity, mTraceEvent)
            DetailDownloadUtils.detailInitDownload(detailViewHolder, false)
            if (mDownloadBinding.ivReserve.visibility == View.VISIBLE) {
                showReserveBtn(isShowReserveBtn())
            }
        }
    }

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

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

            mShowConcernOnMenu = true
        }
    }

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

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

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

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()

        if (mNewGameDetailEntity == null) return

        updateGameDetailTopArea()
        controlReserveBtn()
        detailViewHolder.mDownloadPb.buttonStyle = detailViewHolder.mDownloadPb.buttonStyle
        if (detailViewHolder.mDownloadTips.visibility == View.VISIBLE) {
            detailViewHolder.mDownloadTips.setDownloadTipsAnimation(detailViewHolder.mDownloadTips.isAnimating)
        }
        mBodyBinding.collapsingToolbar.setContentScrimColor(R.color.background_white.toColor(requireContext()))
        mBodyBinding.gamedetailAppbar.setBackgroundColor(R.color.background_white.toColor(requireContext()))
        mBodyBinding.toolbarGapView.setBackgroundColor(R.color.background.toColor(requireContext()))
        mBodyBinding.gamedetailTvName.setTextColor(R.color.text_title.toColor(requireContext()))
        mBodyBinding.gameBigEvent.background = R.drawable.bg_game_big_event.toDrawable(requireContext())
        mBodyBinding.gameBigEvent.setTextColor(R.color.text_subtitleDesc.toColor(requireContext()))
        mBodyBinding.gamedetailGametag.children.forEach {
            if (it is TextView) {
                it.setTextColor(R.color.text_title.toColor(requireContext()))
                it.background = (it.background as GradientDrawable).apply {
                    setStroke(0.5F.dip2px(), Color.parseColor(if (mIsDarkModeOn) "#33FFFFFF" else "#CCCCCC"))
                }
            }
            if (it is ImageView) {
                if (mIsDarkModeOn) it.setColorFilter(R.color.text_title.toColor(requireContext())) else it.colorFilter =
                    null
                it.background = (it.background as GradientDrawable).apply {
                    setStroke(0.5F.dip2px(), Color.parseColor(if (mIsDarkModeOn) "#33FFFFFF" else "#CCCCCC"))
                }
            }
        }
        for (i in 0 until mBodyBinding.tabLayout.tabCount) {
            val tab = mBodyBinding.tabLayout.getTabAt(i) ?: continue
            val textView = tab.customView?.findViewById(R.id.tab_title) as? TextView ?: break
            TextViewCompat.setTextAppearance(textView, R.style.TabLayoutTextAppearance)
        }
        mBinding.detailLlBottom.detailLlBottom.setBackgroundColor(R.color.background.toColor(requireContext()))
        updateToolbarStyle(!mViewModel.displayTopVideo || mBodyBinding.gamedetailThumbSmall.visibility == View.VISIBLE)
        mViewModel.gameDetailLiveData.value?.data?.let {
            if (it.isShowContentCard(mGameEntity)) {
                initGameContentCard(it.contentCard)
            }
        }
    }

    override fun scrollToTop() {
        val fragment = mFragmentsList.safelyGetInRelease(mBodyBinding.gamedetailVp.currentItem)
        if (fragment is IScrollable && fragment.isAdded) {
            fragment.scrollToTop()
        }
        mBodyBinding.gamedetailAppbar.setExpanded(true)
    }

    companion object {
        const val TAB_DESC = "详情"
        const val TAB_TRENDS = "专区"
        const val TAB_ARCHIVE = "云存档"
        const val TAB_RATING = "评价"
        const val TAB_BBS = "论坛"

        const val SKIP_DESC = "skipDesc"
        const val SKIP_FULI = "skipFuli"
        const val SKIP_RATING = "skipRatting"
        const val OPEN_APPBAR = "openappbar"
        const val CLOSE_APPBAR = "closeappbar"
        const val SCROLL_TO_KAIFU = "scrollToKaiFu"
        const val EB_SCROLLING = "EB_SCROLLING"
        const val INITIAL_DELAY = 500L
        const val CONTENT_CARD_LOOP_TIME = 3000L

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

    class LooperHandle(fragment: GameDetailFragment) : Handler(
        Looper.getMainLooper()
    ) {
        private val mWeakReference: WeakReference<GameDetailFragment> = WeakReference(fragment)

        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            val fragment = mWeakReference.get()
            if (fragment != null) {
                if (msg.what == fragment.mServerLooperKey) {
                    fragment.scrollToNextContent(fragment.mContentCardServerVp)
                }
                fragment.startAutoPlay(msg.what)
            }
        }
    }
}
