package com.gh.gamecenter.gamedetail.detail

import android.animation.ValueAnimator
import android.app.Activity
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.TransitionDrawable
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.isVisible
import androidx.core.view.iterator
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import androidx.viewpager2.widget.ViewPager2
import com.gh.common.util.*
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.LazyFragment
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.json.json
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.ScrollEventListener
import com.gh.gamecenter.common.view.TextBannerView
import com.gh.gamecenter.common.view.TextBannerView.Companion.ANIMATION_DURATION
import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.provider.IFloatingWindowProvider
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.FragmentGameDetailBinding
import com.gh.gamecenter.databinding.ItemGameDetailDataInfoBinding
import com.gh.gamecenter.databinding.ItemGameDetailFunctionTagBinding
import com.gh.gamecenter.databinding.LayoutGuideGameDetailFunctionTagBinding
import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.eventbus.EBStar
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.GameDetailWrapperFragment
import com.gh.gamecenter.gamedetail.detail.adapter.GameDetailCoverAdapter
import com.gh.gamecenter.gamedetail.detail.adapter.GameDetailListAdapter
import com.gh.gamecenter.gamedetail.detail.adapter.GameLibaoAdapter
import com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder.Companion.getGameStatus
import com.gh.gamecenter.gamedetail.detail.viewholder.GameDetailCommentItemViewHolder
import com.gh.gamecenter.gamedetail.dialog.GameBigEventDialogFragment
import com.gh.gamecenter.gamedetail.dialog.GameFunctionDialogFragment
import com.gh.gamecenter.gamedetail.entity.GameDetailDataInfo
import com.gh.gamecenter.gamedetail.entity.GameDetailInfoTag
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
import com.gh.gamecenter.gamedetail.rating.RatingFragment
import com.gh.gamecenter.gamedetail.video.GameDetailScrollCalculatorHelper
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.livedata.EventObserver
import com.gh.gamecenter.tag.TagsActivity
import com.gh.gamecenter.video.detail.CustomManager
import com.halo.assistant.HaloApp
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import com.therouter.TheRouter
import io.reactivex.disposables.CompositeDisposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.*
import kotlin.math.abs

class GameDetailFragment : LazyFragment(), IScrollable {
    private lateinit var binding: FragmentGameDetailBinding
    private lateinit var viewModel: GameDetailViewModel
    private lateinit var scrollCalculatorHelper: GameDetailScrollCalculatorHelper
    private val coverAdapter by lazy {
        GameDetailCoverAdapter(
            requireContext(),
            this@GameDetailFragment,
            viewModel,
            scrollCalculatorHelper
        ) {
            binding.coverSfv.isVisible = shouldShowCoverFilter && it
        }
    }
    private val coverLayoutManager by lazy {
        LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
    }
    private val snapHelper by lazy { GameDetailCoverSnapHelper() }
    private val coverScrollEventListener by lazy { ScrollEventListener(binding.coverRv) }
    private val detailListAdapter by lazy {
        GameDetailListAdapter(downloadButton, viewModel, viewLifecycleOwner)
    }
    private val detailLayoutManager by lazy { LinearLayoutManager(requireContext()) }

    private var isCoverHeightAnimating = false
    private var coverPosition = 0
    private var bigEventTransitionDrawable: TransitionDrawable? = null
    private var gameEntity: GameEntity? = null
    private val downloadButton
        get() = (parentFragment as? GameDetailWrapperFragment)?.provideDownloadButton()
    private val gameStatus
        get() = getGameStatus(downloadButton?.buttonStyle, viewModel)

    private var functionTagGuide: ViewGroup? = null
    private var compositeDisposable = CompositeDisposable()
    private var isPauseCoverVideo = false
    private var isPlayingWhenPause = false // 判断执行onPause时视频是否在播放中
    private var isFirstLoad = true
    private var showTopGameInfo = false
    private var shouldShowCoverFilter = false

    override fun getRealLayoutId(): Int = R.layout.fragment_game_detail

    override fun onRealLayoutInflated(inflatedView: View) {
        super.onRealLayoutInflated(inflatedView)
        binding = FragmentGameDetailBinding.bind(inflatedView)
        scrollCalculatorHelper = GameDetailScrollCalculatorHelper(binding.coverRv, R.id.player, 0)
    }

    override fun onFragmentFirstVisible() {
        super.onFragmentFirstVisible()

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

        initDetailRv()
        observeData()

        binding.gamedetailAppbar.addOnOffsetChangedListener { _, verticalOffset ->
            if (!isAdded) return@addOnOffsetChangedListener

            val absVerticalOffset = abs(verticalOffset)
            val coverHeight = binding.coverRv.height
            if (viewModel.displayCoverVideo && coverHeight != 0) {
                val player = scrollCalculatorHelper.currentPlayer
                if (absVerticalOffset > coverHeight && !isPauseCoverVideo && player?.currentState == GSYVideoView.CURRENT_STATE_PLAYING) {
                    isPauseCoverVideo = true
                    pauseVideo()
                } else if (absVerticalOffset == 0 && isPauseCoverVideo && player?.currentState == GSYVideoView.CURRENT_STATE_PAUSE) {
                    isPauseCoverVideo = false
                    resumeVideo()
                }
            }

            val isGameIconGone = absVerticalOffset > coverHeight + 16F.dip2px() + binding.gameIconIv.height / 2F
            if (showTopGameInfo != isGameIconGone) {
                showTopGameInfo = isGameIconGone
                showTopGameInfoWithAnimation(isGameIconGone)
            }
        }
    }

    private fun showTopGameInfoWithAnimation(isShow: Boolean) {
        val translationY = if (isShow) 0F else (-44F).dip2px().toFloat()
        binding.topGameInfoContainer.animate().translationY(translationY).apply {
            duration = TOP_GAME_INFO_ANIMATION_DURATION
        }.start()
    }

    private fun observeData() {
        viewModel.coverListLiveData.observeNonNull(viewLifecycleOwner) {
            initCover()
            coverAdapter.submitList(it)
            binding.run {
                val tabNameList = it.map { coverEntity -> coverEntity.tabName }.distinct()
                shouldShowCoverFilter = tabNameList.size >= 2
                galleryIndicator.goneIf(viewModel.defaultCoverEntity?.gallery == null) {
                    galleryIndicator.text = "${viewModel.defaultCoverEntity?.galleryIndex?.plus(1)}/${viewModel.defaultCoverEntity?.galleryCount}"
                }
                coverSfv.goneIf(!shouldShowCoverFilter) {
                    val defaultTabPosition =
                        tabNameList.indexOfFirst { tabName -> viewModel.defaultCoverEntity?.tabName == tabName }
                    viewModel.coverTabSequence = defaultTabPosition + 1
                    viewModel.coverTabName = viewModel.defaultCoverEntity?.tabName ?: ""
                    coverSfv.setItemList(tabNameList, if (defaultTabPosition != -1) defaultTabPosition else 0)
                    coverSfv.setOnCheckedCallback { position ->
                        val checkedText = tabNameList.getOrNull(position)
                        val currentCoverEntity = it.getOrNull(coverPosition)
                        viewModel.coverTabSequence = position + 1
                        viewModel.coverTabName = checkedText ?: ""
                        SensorsBridge.trackEvent("GameDetailMediaTabClick", json {
                            "game_id" to gameEntity?.id
                            "game_name" to gameEntity?.name
                            "sequence" to viewModel.coverTabSequence
                            "tab_name" to viewModel.coverTabName
                            "game_type" to gameEntity?.categoryChinese
                        })
                        if (currentCoverEntity?.tabName == checkedText) return@setOnCheckedCallback

                        val checkPosition = it.indexOfFirst { coverEntity -> coverEntity.tabName == checkedText }
                        if (checkPosition != -1) {
                            setCurrentCoverItem(checkPosition)
                        }
                    }
                }
                coverRv.scrollToPosition(viewModel.defaultCoverEntity?.index ?: 0)
                coverPosition = viewModel.defaultCoverEntity?.index ?: 0
                coverContainer.visibility = View.VISIBLE
            }

            // 未有缓存时，为避免影响页面加载，延迟自动播放视频
            val delayTime = if (viewModel.isTopVideoPartlyCached(viewModel.defaultCoverEntity?.video?.url ?: "")) 0 else COVER_VIDEO_INITIAL_DELAY
            postDelayedRunnable({
                if (activity != null && activity?.isFinishing != true) {
                    notifyScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE)
                }
            }, delayTime)
        }

        viewModel.basicInfoLiveData.observeNonNull(viewLifecycleOwner) {
            initBasicInfo(it)
        }

        viewModel.bigEventLiveData.observeNonNull(viewLifecycleOwner) {
            GameBigEventDialogFragment.show(
                requireContext(),
                gameEntity,
                it
            )
        }

        viewModel.dataInfoLiveData.observeNonNull(viewLifecycleOwner) {
            initDataInfo(it)
        }

        viewModel.infoTagLiveData.observeNonNull(viewLifecycleOwner) {
            initInfoTags(it)
        }

        viewModel.detailDataListLiveData.observeNonNull(viewLifecycleOwner) {
            if (it.isNotEmpty()) {
                binding.coordinator.isVisible = true
                binding.detailRv.isVisible = true
                binding.detailListNoneData.isVisible = false
                binding.reuseNoneData.root.isVisible = false
                detailListAdapter.submitList(it)

                val openVideoStreaming = arguments?.getBoolean(EntranceConsts.KEY_OPEN_VIDEO_STREAMING, false) ?: false
                if (openVideoStreaming && isFirstLoad) {
                    it.find { item -> item.linkGameVideo != null }?.let { item ->
                        val firstVideo = item.linkGameVideo?.video?.firstOrNull()
                        DirectUtils.directToVideoDetail(
                            requireContext(), firstVideo?.id ?: "", firstVideo?.id ?: "", path = "游戏详情-介绍视频"
                        )
                    }
                }

                if (isFirstLoad) {
                    var isPerformedSuccess = false
                    val performContentCardClickType = arguments?.getString(EntranceConsts.KEY_PERFORM_CONTENT_CARD_CLICK_TYPE)
                    if (performContentCardClickType != null) {
                        isPerformedSuccess = viewModel.performContentCardClicked(performContentCardClickType)
                    }
                    if (arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_SERVER) == true) {
                        isPerformedSuccess = viewModel.performScrollToServer()
                    }
                    if (arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO) == true) {
                        isPerformedSuccess = viewModel.performScrollToLibao()
                    }

                    val infoTagData = viewModel.infoTagLiveData.value
                    val showFunctionTagGuide = !infoTagData?.infoTags.isNullOrEmpty() && SPUtils.getBoolean(Constants.SP_SHOW_GAME_DETAIL_FUNCTION_TAG_GUIDE, true)
                    if (!isPerformedSuccess && showFunctionTagGuide) {
                        binding.coverRv.post {
                            showFunctionTagGuide()
                        }
                    }
                }

                isFirstLoad = false
            } else if (viewModel.basicInfoLiveData.value == null) {
                binding.coordinator.isVisible = false
                binding.reuseNoneData.root.isVisible = true
            } else {
                binding.coordinator.isVisible = true
                binding.detailRv.isVisible = false
                binding.detailListNoneData.isVisible = true
            }
        }

        viewModel.scrollToListPositionLiveData.observe(viewLifecycleOwner, EventObserver { link ->
            val position = viewModel.detailDataListLiveData.value?.indexOfFirst {
                if (!link.type.isNullOrEmpty()) {
                    it.type == link.type
                } else {
                    it.id == link.link
                }
            } ?: -1
            if (position != -1) {
                binding.gamedetailAppbar.setExpanded(false, true)
                detailLayoutManager.scrollToPositionWithOffset(position, binding.topGameInfoContainer.height)
            }
        })
    }

    private fun initDetailRv() {
        binding.detailRv.run {
            itemAnimator = null
            layoutManager = detailLayoutManager
            adapter = detailListAdapter
            addOnScrollListener(object : OnScrollListener() {
                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                    super.onScrollStateChanged(recyclerView, newState)
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        val pageDepth = detailLayoutManager.findLastCompletelyVisibleItemPosition() + 1
                        viewModel.pageDepth = pageDepth.coerceAtLeast(viewModel.pageDepth)
                    }
                    if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                        EventBus.getDefault().post(EBTypeChange(GameDetailWrapperFragment.EB_SCROLLING, 0))
                    }
                }
            })
        }
    }

    private fun initCover() {
        binding.run {
            coverRv.layoutManager = coverLayoutManager
            coverRv.adapter = coverAdapter
            (coverRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
            coverRv.isNestedScrollingEnabled = false
            coverRv.onFlingListener = null
            snapHelper.attachToRecyclerView(coverRv)
            coverRv.addOnScrollListener(coverScrollEventListener.apply {
                registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
                    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
                        super.onPageScrolled(position, positionOffset, positionOffsetPixels)
                        startCoverHeightAnimationOnPageScrolled()
                        updateCoverGalleryIndicator()
                        coverSfv.isVisible = shouldShowCoverFilter
                    }

                    override fun onPageSelected(position: Int) {
                        super.onPageSelected(position)
                        if (position != coverPosition) {
                            val selectedCoverEntity = viewModel.coverListLiveData.value?.getOrNull(position)
                            coverPosition = position
                            galleryIndicator.goneIf(selectedCoverEntity?.gallery == null)
                            if (shouldShowCoverFilter) {
                                val sfvPosition = coverSfv.getItemList().indexOfFirst { it == selectedCoverEntity?.tabName }
                                coverSfv.setChecked(sfvPosition, true)
                            }
                        }
                    }

                    override fun onPageScrollStateChanged(state: Int) {
                        super.onPageScrollStateChanged(state)
                        notifyScrollStateChanged(state)
                    }
                })
            })
        }
    }

    private fun startCoverHeightAnimationOnPageScrolled() {
        val firstCompletelyVisibleItemPosition =
            coverLayoutManager.findFirstCompletelyVisibleItemPosition()
        if (!isCoverHeightAnimating && firstCompletelyVisibleItemPosition > -1) {
            val firstCompletelyVisibleItemView =
                coverLayoutManager.findViewByPosition(firstCompletelyVisibleItemPosition)
            firstCompletelyVisibleItemView?.post {
                if (firstCompletelyVisibleItemView.height > 0 && binding.coverRv.height != firstCompletelyVisibleItemView.height) {
                    startCoverHeightAnimation(binding.coverRv.height, firstCompletelyVisibleItemView.height)
                }
            }
        }
    }

    private fun updateCoverGalleryIndicator() {
        val lastCompletelyVisibleItemPosition =
            coverLayoutManager.findLastCompletelyVisibleItemPosition()
        if (lastCompletelyVisibleItemPosition > -1) {
            val lastCompletelyVisibleCoverEntity = viewModel.coverListLiveData.value?.getOrNull(lastCompletelyVisibleItemPosition)
            val displayCurrentIndex = lastCompletelyVisibleCoverEntity?.galleryIndex?.plus(1)
            val galleryCount = lastCompletelyVisibleCoverEntity?.galleryCount
            if (displayCurrentIndex != null && galleryCount != null) {
                binding.galleryIndicator.text = "${displayCurrentIndex}/${galleryCount}"
            }
        }
    }

    private fun initBasicInfo(basicInfo: GameEntity) {
        binding.run {
            gameIconIv.displayGameIcon(basicInfo)
            topGameIconIv.displayGameIcon(basicInfo)
            if (basicInfo.subtitle.isNotEmpty() || basicInfo.advanceDownload) {
                val gameSubtitleStyle = basicInfo.subtitleStyle
                val advanceDownload = basicInfo.advanceDownload
                val subtitleLayout = FrameLayout(requireContext())
                val subtitleTextView = TextView(requireContext()).apply {
                    layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, 14F.dip2px())
                    text = if (advanceDownload) "预下载" else basicInfo.subtitle
                    textSize = 10F
                    setPadding(2F.dip2px(), 0, 2F.dip2px(), 0)
                    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(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
                        background = com.gh.gamecenter.feature.R.drawable.bg_advance_download_game_subtitle.toDrawable(requireContext())
                    }
                }
                subtitleLayout.addView(
                    subtitleTextView,
                    FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, 14F.dip2px()).apply {
                        leftMargin = 4F.dip2px()
                    })
                val subtitleBitmap = subtitleLayout.convertViewToBitmap()
                basicInfo.name?.let { name ->
                    val ssb = SpannableStringBuilder("$name ").apply {
                        subtitleBitmap?.let {
                            setSpan(
                                CenterImageSpan(
                                    context,
                                    it
                                ), name.length, name.length + 1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE
                            )
                        }
                    }
                    topGameNameTv.text = ssb
                    gameNameTv.text = ssb
                }
            } else {
                gameNameTv.text = basicInfo.name
                topGameNameTv.text = basicInfo.name
            }
            gameNameTv.marqueeOnce()
            gameNameTv.setOnClickListener { gameNameTv.marqueeAgain() }
            topGameNameTv.setOnClickListener { topGameNameTv.marqueeAgain() }
            officialEntryIv.isVisible = basicInfo.officialEntry
            descTv.text = basicInfo.sellingPointsText

            val showTags = if (basicInfo.officialEntry) {
                basicInfo.sellingPointTags.take(3)
            } else {
                basicInfo.sellingPointTags.take(3).ifEmpty { basicInfo.gameTags.take(3) }
            }
            gameEntity?.gameType = showTags.joinToString("-") { it.name }
            binding.tagContainer.removeAllViews()
            showTags.forEachIndexed { index, tag ->
                if (index != 0) {
                    tagContainer.addView(
                        getTagTextView(" · "),
                        LinearLayout.LayoutParams.WRAP_CONTENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT
                    )
                }

                val tagView = getTagTextView(tag.name).apply {
                    setOnClickListener {
                        NewLogUtils.logGameDetailTagClick(
                            gameEntity?.id ?: "",
                            gameEntity?.name ?: "",
                            tag.id,
                            tag.name,
                            tag.isTop
                        )
                        SensorsBridge.trackGameDetailModuleClick(
                            gameEntity?.id,
                            gameEntity?.name,
                            gameEntity?.categoryChinese,
                            "组件内容",
                            "卖点标签",
                            null,
                            null,
                            null,
                            null,
                            gameStatus = gameStatus
                        )
                        startActivity(TagsActivity.getIntent(requireContext(), tag.name, tag.name, mEntrance, "游戏介绍"))
                    }
                }
                tagContainer.addView(
                    tagView,
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }

            val showDiscount = basicInfo.welfareText?.status == "on" && !basicInfo.welfareText?.discount.isNullOrEmpty()
            val showScoreContainer = basicInfo.star != -1F && !showDiscount
            scoreContainer.goneIf(!showScoreContainer) {
                val showScore = (gameEntity?.commentCount ?: 0) > 3
                scoreIv.imageTintList = ColorStateList.valueOf(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
                scoreIv.setImageResource(if (showScore) R.drawable.text_game_detail_score else R.drawable.text_game_detail_no_score)
                scoreTv.goneIf(!showScore) {
                    scoreTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
                    scoreTv.text = if (basicInfo.star == 10F) "10" else String.format(Locale.getDefault(), "%.1f", basicInfo.star)
                }
                scoreContainer.setOnClickListener {
                    viewModel.performTabSelected(GameDetailTabEntity.TYPE_COMMENT)
                }
            }
            discountContainer.goneIf(!showDiscount) {
                discountTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
                discountTextTv.text = basicInfo.welfareText?.text
                discountTv.text = basicInfo.welfareText?.discount
            }
            bigEventContainer.goneIf(basicInfo.event.isNullOrEmpty()) {
                basicInfo.event?.let {
                    bigEventTransitionDrawable = R.drawable.transition_bg_game_detail_big_event.toDrawable(requireContext()) as TransitionDrawable
                    bigEventBackground.background = bigEventTransitionDrawable
                    val index = if (binding.bigEventBannerView.currentIndex != -1) binding.bigEventBannerView.currentIndex else 0
                    val isHighLight = it.getOrNull(index)?.highLight ?: false
                    if (isHighLight) bigEventTransitionDrawable?.reverseTransition(0)

                    bigEventBannerView.setOnClickListener { _ ->
                        SensorsBridge.trackGameDetailModuleClick(
                            gameEntity?.id,
                            gameEntity?.name,
                            gameEntity?.categoryChinese,
                            "组件内容",
                            "大事件",
                            null,
                            null,
                            null,
                            null,
                            gameStatus = gameStatus
                        )
                        viewModel.getBigEvent()
                    }
                    bigEventBannerView.setDataList(it.map { event ->
                        var eventStr = if (event.highLight) {
                            "${TimeUtils.getFormatTime(event.time, "MM-dd")}${TimeUtils.getDayString(event.time)}：${event.content}"
                        } else {
                            if (TimeUtils.getBeforeDays(event.time) <= 15) "${
                                TimeUtils.getFormatTime(event.time, "MM-dd")
                            }${TimeUtils.getDayString(event.time)}：${event.content}" else "游戏大事件"
                        }
                        if (eventStr.contains("\n")) eventStr = eventStr.substring(0, eventStr.indexOf("\n"))
                        TextBannerView.BannerTextData(text = eventStr, highLight = event.highLight)
                    })
                    bigEventBannerView.onTextUpdateListener = { lastIndex, nextIndex ->
                        if (lastIndex in it.indices && nextIndex in it.indices) {
                            val lastEvent = it[lastIndex]
                            val nextEvent = it[nextIndex]
                            if (lastEvent.highLight != nextEvent.highLight) {
                                // 背景颜色变化的过渡动画
                                bigEventTransitionDrawable?.reverseTransition(BIG_EVENT_TRANSITION_DURATION)
                            }
                        }
                        bigEventBannerView.currentView?.post {
                            val currentWidth = (bigEventBannerView.nextView?.width ?: 0) + 54F.dip2px()
                            val targetWidth = (bigEventBannerView.currentView?.width ?: 0) + 54F.dip2px()
                            // 宽度变化的过渡动画
                            ValueAnimator.ofInt(currentWidth, targetWidth).apply {
                                duration = ANIMATION_DURATION
                                addUpdateListener { va ->
                                    bigEventBackground.updateLayoutParams {
                                        width = va.animatedValue as Int
                                    }
                                }
                            }.start()
                        }
                    }
                    bigEventBannerView.startBannerLoop()
                    bigEventContainer.post {
                        ConstraintSet().apply {
                            clone(bigEventContainer)
                            clear(R.id.bigEventBackground, ConstraintSet.END)
                        }.applyTo(bigEventContainer)
                        bigEventBackground.updateLayoutParams { width = bigEventContainer.width }
                    }
                }
            }
        }
    }

    private fun getTagTextView(name: String) = TextView(requireContext()).apply {
        text = name
        textSize = 11F
        includeFontPadding = false
        setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(requireContext()))
    }

    private fun initDataInfo(dataList: List<GameDetailDataInfo>) {
        binding.dataContainer.removeAllViews()
        dataList.forEachIndexed { index, dataInfo ->
            binding.dataContainer.addView(getDataInfoItemView(dataInfo), 68F.dip2px(), 46F.dip2px())
            if (index != dataList.size - 1) {
                binding.dataContainer.addView(View(requireContext()).apply {
                    setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(requireContext()))
                }, 1F.dip2px(), 24F.dip2px())
            }
        }
    }

    private fun initInfoTags(gameDetailInfoTag: GameDetailInfoTag) {
        val isSpeedStatusOn = gameDetailInfoTag.requestSpeedStatus == "on"
        val showInfoTags = gameDetailInfoTag.infoTags.isNotEmpty()
        binding.infoTagContainer.goneIf(!isSpeedStatusOn && !showInfoTags) {
            binding.accelerateTv.goneIf(!isSpeedStatusOn) {
                if (gameDetailInfoTag.infoTags.isEmpty()) {
                    binding.infoTagContainer.updateLayoutParams<LinearLayout.LayoutParams> { width = LinearLayout.LayoutParams.WRAP_CONTENT }
                    binding.accelerateTipsTv.visibility = View.VISIBLE
                }
                binding.accelerateTv.setOnClickListener {
                    it.context.ifLogin("游戏详情-求加速") {
                        NewFlatLogUtils.logGameDetailClickForAccelerate(gameEntity?.id ?: "", gameEntity?.name ?: "")
                        SensorsBridge.trackGameDetailModuleClick(
                            gameEntity?.id,
                            gameEntity?.name,
                            gameEntity?.categoryChinese,
                            "组件内容",
                            "功能标签",
                            null,
                            null,
                            null,
                            null,
                            gameStatus = gameStatus
                        )
                        DialogHelper.showDialog(
                            requireContext(), "版本求加速", "如果游戏需要加速版本，您可以提交申请，让小助手尽快研究给您喔！",
                            "提交申请", "取消", {
                                viewModel.postRequestSpeed()
                            }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
                        )
                    }
                }
            }
            binding.functionTagContainer.goneIf(!showInfoTags) {
                val iterator = binding.functionTagContainer.iterator()
                while (iterator.hasNext()) {
                    val childView = iterator.next()
                    if (childView.id != R.id.moreContainer) {
                        iterator.remove()
                    }
                }
                val showTags = gameDetailInfoTag.infoTags.take(3)
                showTags.forEachIndexed { index, infoTag ->
                    binding.functionTagContainer.addView(
                        getFunctionTagView(infoTag),
                        index,
                        LinearLayout.LayoutParams(
                            LinearLayout.LayoutParams.WRAP_CONTENT,
                            LinearLayout.LayoutParams.WRAP_CONTENT
                        ).apply {
                            if (index != 0) {
                                setMargins(8F.dip2px(), 0, 0, 0)
                            }
                        }
                    )
                }
                binding.moreContainer.goneIf(gameDetailInfoTag.infoTags.size <= 3) {
                    binding.moreTv.text = "+${gameDetailInfoTag.infoTags.size - 3}"
                }
                binding.infoTagContainer.setOnClickListener {
                    SensorsBridge.trackGameDetailModuleClick(
                        gameEntity?.id,
                        gameEntity?.name,
                        gameEntity?.categoryChinese,
                        "组件内容",
                        "功能标签",
                        null,
                        null,
                        null,
                        null,
                        gameStatus = gameStatus
                    )
                    GameFunctionDialogFragment.show(requireContext(), gameEntity, gameDetailInfoTag.infoTags, gameDetailInfoTag.link)
                }
            }
        }
    }

    private fun showFunctionTagGuide() {
        if (!isResumed) return

        val decorView = activity?.window?.decorView as? FrameLayout
        LayoutGuideGameDetailFunctionTagBinding.inflate(layoutInflater, decorView, true).run {
            functionTagGuide = root
            val screenWidth = DisplayUtils.getScreenWidth(requireActivity())
            val infoTagLocation = IntArray(2)
            binding.infoTagContainer.getLocationInWindow(infoTagLocation)
            val top = (infoTagLocation[1] - 12F.dip2px()).toFloat()
            root.targetRect.set(8F.dip2px().toFloat(), top, (screenWidth - 8F.dip2px()).toFloat(), top + 53F.dip2px())
            guideIv.translationY = top - 56F.dip2px()
            containerView.translationY = infoTagLocation[1].toFloat()
            accelerateView.goneIf(viewModel.infoTagLiveData.value?.requestSpeedStatus != "on") {
                accelerateView.translationY = infoTagLocation[1].toFloat()
                accelerateView.setOnClickListener {
                    hideFunctionTagGuide()
                    binding.accelerateTv.performClick()
                }
            }
            containerView.setOnClickListener {
                hideFunctionTagGuide()
                binding.infoTagContainer.performClick()
            }
            root.setOnClickListener {
                hideFunctionTagGuide()
            }
        }
        SensorsBridge.trackEvent("GameDetailFuncLabelGuide", json {
            "game_id" to viewModel.game?.id
            "game_name" to viewModel.game?.name
        })
    }

    private fun hideFunctionTagGuide() {
        val decorView = activity?.window?.decorView as? FrameLayout
        functionTagGuide?.animate()?.alpha(0F)?.setDuration(300L)?.apply {
            doOnEnd {
                decorView?.removeView(functionTagGuide)
                functionTagGuide = null
            }
        }?.start()
        SPUtils.setBoolean(Constants.SP_SHOW_GAME_DETAIL_FUNCTION_TAG_GUIDE, false)
    }

    private fun getFunctionTagView(infoTag: GameDetailInfoTag.InfoTag) =
        ItemGameDetailFunctionTagBinding.inflate(layoutInflater).apply {
            ImageUtils.display(iconIv, infoTag.icon)
            nameTv.text = infoTag.name
        }.root

    private fun getDataInfoItemView(dataInfo: GameDetailDataInfo) = ItemGameDetailDataInfoBinding.inflate(layoutInflater).apply {
        nameTv.text = dataInfo.nameCn
        when (dataInfo.name) {
            "ranking" -> {
                if (dataInfo.ranking != null) {
                    nameTv.text = dataInfo.ranking.columnName
                    infoTv.text = "#${dataInfo.ranking.no}"
                    infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
                    infoTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
                    infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
                    root.setOnClickListener {
                        SensorsBridge.trackGameDetailModuleClick(
                            gameEntity?.id,
                            gameEntity?.name,
                            gameEntity?.categoryChinese,
                            "组件内容",
                            "数据信息栏",
                            null,
                            null,
                            null,
                            null,
                            gameStatus = gameStatus
                        )
                        DirectUtils.directToColumnCollection(
                            requireContext(),
                            dataInfo.ranking.collectionId,
                            entrance = mEntrance,
                            columnName = dataInfo.ranking.columnName,
                        )
                    }
                }
            }
            "real_name" -> {
                if (dataInfo.realName != null) {
                    infoTv.text = if (dataInfo.realName.state == "yes") "有" else "无"
                    if (dataInfo.realName.certificationScreenshot.isNotEmpty()) {
                        infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
                        root.setOnClickListener {
                            SensorsBridge.trackGameDetailModuleClick(
                                gameEntity?.id,
                                gameEntity?.name,
                                gameEntity?.categoryChinese,
                                "组件内容",
                                "数据信息栏",
                                null,
                                null,
                                null,
                                null,
                                gameStatus = gameStatus
                            )
                            startActivity(
                                ImageViewerActivity.getSingleIntent(
                                    requireContext(),
                                    dataInfo.realName.certificationScreenshot,
                                    false
                                )
                            )
                        }
                    } else {
                        infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
                    }
                }
            }
            else -> {
                infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
                infoTv.text = dataInfo.value
            }
        }
    }.root

    private fun notifyScrollStateChanged(state: Int) {
        val firstVisibleItem = coverLayoutManager.findFirstVisibleItemPosition()
        val lastVisibleItem = coverLayoutManager.findLastVisibleItemPosition()
        scrollCalculatorHelper.onScrollStateChanged(firstVisibleItem, lastVisibleItem, state)
    }

    private fun setCurrentCoverItem(position: Int) {
        if (position == coverPosition) return

        coverScrollEventListener.notifyProgrammaticScroll(position, true)
        coverLayoutManager.scrollToPositionWithOffset(position, 0)
        coverPosition = position
    }

    override fun onFragmentPause() {
        super.onFragmentPause()
        isPlayingWhenPause = if (scrollCalculatorHelper.currentPlayer != null) {
            CustomManager.getCustomManager(scrollCalculatorHelper.currentPlayer!!.getKey()).isPlaying || (isPlayingWhenPause && viewModel.isSkipOnPageSelected)
        } else {
            false
        }
        pauseVideo()
        binding.bigEventBannerView.stopBannerLoop()
    }

    override fun onFragmentResume() {
        super.onFragmentResume()
        if (!isPauseCoverVideo && isPlayingWhenPause) {
            resumeVideo()
        }

        if (!viewModel.basicInfoLiveData.value?.event.isNullOrEmpty()) {
            binding.bigEventBannerView.startBannerLoop()
        }
    }

    private fun pauseVideo() {
        val currentPlayer = scrollCalculatorHelper.currentPlayer
        if (currentPlayer != null) {
            currentPlayer.onVideoPause()
            val currentPosition = currentPlayer.getCurrentPosition()

            val videoUrl = currentPlayer.getUrl()
            if (videoUrl.isNotEmpty()) {
                ScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(videoUrl), currentPosition)
            }
        }
    }

    private fun resumeVideo() {
        val currentPlayer = scrollCalculatorHelper.currentPlayer
        if (currentPlayer != null) {
            val videoUrl = currentPlayer.getUrl()
            if (videoUrl.isNotEmpty()) {
                val position = ScrollCalculatorHelper.getPlaySchedule(MD5Utils.getContentMD5(videoUrl))
                //这里必须要延迟操作，否则会白屏
                mBaseHandler.postDelayed({
                    if (!lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) return@postDelayed
                    if (position != 0L) {
                        scrollCalculatorHelper.currentPlayer?.seekTo(position)
                        scrollCalculatorHelper.currentPlayer?.onVideoResume(false)
                    } else {
                        scrollCalculatorHelper.currentPlayer?.release()
                    }
                }, 50)
            }
        }
    }

    private fun showFloatingWindowIfNeeded() {
        val floatingWindowProvider = TheRouter.get(IFloatingWindowProvider::class.java)

        floatingWindowProvider?.getAndShowFloatingWindow(
            gameEntity?.id ?: "",
            gameEntity?.name ?: "",
            "游戏详情",
            this,
            binding.detailRv
        )?.let {
            compositeDisposable.add(it)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        compositeDisposable.dispose()
        if (::scrollCalculatorHelper.isInitialized) {
            scrollCalculatorHelper.release()
        }
    }

    private fun startCoverHeightAnimation(startHeight: Int, targetHeight: Int) {
        if (isCoverHeightAnimating) return

        ValueAnimator.ofInt(startHeight, targetHeight).apply {
            duration = COVER_HEIGHT_ANIMATION_DURATION
            doOnStart {
                isCoverHeightAnimating = true
            }
            doOnEnd {
                isCoverHeightAnimating = false
            }
            addUpdateListener { va ->
                binding.coverRv.updateLayoutParams<ViewGroup.LayoutParams> {
                    height = va.animatedValue as Int
                }
            }
        }.start()
    }

    override fun scrollToTop() {
        if (::binding.isInitialized) {
            binding.gamedetailAppbar.setExpanded(true)
            binding.detailRv.scrollToPosition(0)
        }
    }

    // 登录事件/礼包状态变更事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(reuse: EBReuse) {
        if (!::viewModel.isInitialized) return
        if (reuse.type == Constants.LOGIN_TAG || (reuse.type == Constants.LIBAO_CHANGED_TAG && !isSupportVisible)) {
            viewModel.getUserRelatedInfoAndGiftStatus()
        }
    }

    // 更新评分
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(data: EBStar) {
        if (!::binding.isInitialized) return
        if (binding.scoreContainer.isVisible) {
            val showScore = data.commentCount > 3
            binding.scoreIv.setImageResource(if (showScore) R.drawable.text_game_detail_score else R.drawable.text_game_detail_no_score)
            binding.scoreTv.goneIf(!showScore) {
                binding.scoreTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
                binding.scoreTv.text = if (data.star == 10F) "10" else String.format(Locale.getDefault(), "%.1f", data.star)
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (!::viewModel.isInitialized) return

        val commentPosition = detailListAdapter.currentList.indexOfFirst { it.linkComment != null }
        if (resultCode == Activity.RESULT_OK) {
            if (GameDetailCommentItemViewHolder.RATING_REPLY_REQUEST == requestCode || GameDetailCommentItemViewHolder.RATING_PATCH_REQUEST == requestCode) {
                SyncDataBetweenPageHelper.resultHandle(data, object : OnSyncCallBack<RatingComment> {
                    override fun onData(dataPosition: Int): RatingComment? {
                        return if (commentPosition != -1) {
                            val commentList = detailListAdapter.currentList[commentPosition].linkComment?.data ?: return null
                            commentList.getOrNull(dataPosition)?.apply {
                                if (GameDetailCommentItemViewHolder.RATING_PATCH_REQUEST == requestCode) {
                                    ignore = gameEntity?.ignoreComment ?: false
                                }
                            }
                        } else null
                    }

                    override fun onNotify(dataPosition: Int) {
                        if (commentPosition != -1) {
                            detailListAdapter.notifyItemChanged(commentPosition)
                        }
                    }
                })
            } else if (requestCode == GameLibaoAdapter.LIBAO_REQUEST) {
                val position = detailListAdapter.currentList.indexOfFirst { it.linkLibao != null }
                if (position != -1) {
                    detailListAdapter.notifyItemChanged(position)
                }
            }
        } else if (requestCode == GameDetailCommentItemViewHolder.RATING_REPLY_REQUEST && resultCode == RatingFragment.RATING_DELETE_RESULT) {
            data?.getParcelableExtra<RatingComment>(RatingComment::class.java.simpleName)?.run {
                if (commentPosition != -1) {
                    val commentList = detailListAdapter.currentList[commentPosition].linkComment?.data ?: return
                    val deleteCommentPosition = commentList.indexOfFirst { it.id == id }
                    if (deleteCommentPosition != -1) {
                        commentList.removeAt(deleteCommentPosition)
                    }
                    detailListAdapter.notifyItemChanged(commentPosition)
                }
            }
        }
    }

    override fun onBackPressed(): Boolean {
        if (functionTagGuide != null) {
            hideFunctionTagGuide()
            return true
        }
        return super.onBackPressed()
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        if (!::binding.isInitialized || !::viewModel.isInitialized) return

        binding.coverSfv.run {
            setIndicatorBackground(com.gh.gamecenter.common.R.drawable.background_shape_white_radius_999.toDrawable(requireContext()))
            setTextColor(
                com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()),
                com.gh.gamecenter.common.R.color.text_aw_primary.toColor(requireContext())
            )
        }
        viewModel.basicInfoLiveData.value?.let { initBasicInfo(it) }

        val dataInfoList = viewModel.dataInfoLiveData.value
        if (!dataInfoList.isNullOrEmpty()) {
            initDataInfo(dataInfoList)
        }

        viewModel.infoTagLiveData.value?.let { initInfoTags(it) }

        detailListAdapter.run { notifyItemRangeChanged(0, itemCount) }
    }

    companion object {
        private const val COVER_HEIGHT_ANIMATION_DURATION = 400L
        private const val COVER_VIDEO_INITIAL_DELAY = 500L
        private const val BIG_EVENT_TRANSITION_DURATION = 1000
        private const val TOP_GAME_INFO_ANIMATION_DURATION = 200L
    }
}