package com.gh.gamecenter.home.custom

import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import com.gh.common.exposure.DefaultExposureStateChangeListener
import com.gh.common.exposure.ExposureManager
import com.gh.common.iinterface.ISearchToolbarTab
import com.gh.common.iinterface.ISmartRefresh
import com.gh.common.iinterface.ISmartRefreshContent
import com.gh.common.iinterface.ISuperiorChain
import com.gh.common.prioritychain.CustomFloatingWindowHandler
import com.gh.common.prioritychain.PriorityChain
import com.gh.common.prioritychain.PullDownPushHandler
import com.gh.common.prioritychain.VideoHandler
import com.gh.common.util.DefaultSearchHintHelper
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.databinding.ReuseNoConnectionBinding
import com.gh.gamecenter.common.databinding.ReuseNoneDataBinding
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.tracker.IBusiness
import com.gh.gamecenter.common.pagelevel.IPageLevelProvider
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.ScrollableLinearLayoutManager
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.FragmentCustomBinding
import com.gh.gamecenter.databinding.LayoutSearchBarBinding
import com.gh.gamecenter.discovery.DiscoveryActivity
import com.gh.gamecenter.discovery.interestedgame.InterestedGameActivity
import com.gh.gamecenter.entity.BottomTab
import com.gh.gamecenter.entity.PullDownPush
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PageLocation
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.exposure.addExposureHelper
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.feature.utils.SentryHelper
import com.gh.gamecenter.game.commoncollection.detail.CustomCommonCollectionDetailActivity
import com.gh.gamecenter.gamedetail.dialog.DspGameDetailDialogFragment
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.home.PageConfigure
import com.gh.gamecenter.home.custom.adapter.CustomPageAdapter
import com.gh.gamecenter.home.custom.floatview.CustomFloatViewAnimationHelper
import com.gh.gamecenter.home.custom.model.CustomPageData
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.livedata.EventObserver
import com.gh.gamecenter.wrapper.BaseTabWrapperFragment
import com.gh.gamecenter.wrapper.MainWrapperViewModel
import com.gh.gamecenter.wrapper.SearchToolbarTabWrapperFragment
import com.gh.gamecenter.wrapper.SearchToolbarTabWrapperViewModel
import com.halo.assistant.HaloApp
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.constant.RefreshState
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode

class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable, IBusiness {

    private var searchToolbarTabWrapperViewModel: SearchToolbarTabWrapperViewModel? = null
    private var mainWrapperViewModel: MainWrapperViewModel? = null

    private val viewModel by viewModels<CustomPageViewModel>(
        factoryProducer = {
            CustomPageViewModel.Factory(com.gh.gamecenter.login.HaloApp.getInstance())
        }
    )

    private lateinit var binding: FragmentCustomBinding

    private var noConnectionBinding: ReuseNoConnectionBinding? = null
    private var noDataBinding: ReuseNoneDataBinding? = null
    private var searchBarBinding: LayoutSearchBarBinding? = null

    private lateinit var adapter: CustomPageAdapter

    private lateinit var layoutManager: ScrollableLinearLayoutManager

    private lateinit var scrollCalculatorHelper: ScrollCalculatorHelper

    private val priorityChain by lazy { PriorityChain() }
    private var superiorChain: ISuperiorChain? = null

    private val floatViewManager = CustomFloatViewAnimationHelper()

    private var customPageId = ""
    private var customPageName = ""
    private var bottomTabId = ""
    private var bottomTabName = ""
    private var bottomTabIndex = -1
    private var tabIndex = -1
    private var showFloatingWindow = true
    private var showPullDownPush = true

    private lateinit var pageLocation: PageLocation

    private val pullDownPushHandler by lazy { PullDownPushHandler(22) }

    private val isInSearchToolbarTabWrapperPage: Boolean
        get() = parentFragment is SearchToolbarTabWrapperFragment

    private val dataWatcher = object : DataWatcher() {
        override fun onDataChanged(downloadEntity: DownloadEntity) {
            adapter.notifyDownload(downloadEntity)

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


        override fun onDataInit(downloadEntity: DownloadEntity) {
            adapter.notifyDownload(downloadEntity)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setNavigationTitle(arguments?.getString(EntranceConsts.KEY_NAVIGATION_TITLE, "") ?: "")
        customPageId = arguments?.getString(EntranceConsts.KEY_CUSTOM_PAGE_ID, "") ?: ""
        customPageName = arguments?.getString(EntranceConsts.KEY_CUSTOM_PAGE_NAME, "") ?: ""
        bottomTabId = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_ID, "") ?: ""
        bottomTabName = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_NAME, "") ?: ""
        bottomTabIndex = arguments?.getInt(EntranceConsts.KEY_BOTTOM_TAB_INDEX, -1) ?: -1
        tabIndex = arguments?.getInt(EntranceConsts.KEY_TAB_INDEX, -1) ?: -1
        showFloatingWindow = arguments?.getBoolean(EntranceConsts.KEY_SHOW_FLOATING_WINDOW, true) ?: true
        showPullDownPush = arguments?.getBoolean(EntranceConsts.KEY_SHOW_PULL_DOWN_PUSH, true) ?: true
        val tabName = arguments?.getString(EntranceConsts.KEY_TAB_NAME, "") ?: ""
        val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
        val multiTabNavName = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, "") ?: ""
        val noTabLinkId = arguments?.getParcelable<LinkEntity>(LinkEntity::class.java.simpleName)?.link ?: ""

        if (isInSearchToolbarTabWrapperPage) {
            searchToolbarTabWrapperViewModel =
                viewModelProviderFromParent(
                    SearchToolbarTabWrapperViewModel.Factory(multiTabNavId, noTabLinkId),
                    multiTabNavId + noTabLinkId
                )
        }
        if (bottomTabId.isNotEmpty()) {
            mainWrapperViewModel = viewModelProviderFromParent(MainWrapperViewModel.Factory(HaloApp.getInstance()))
        }

        val exposureSourceList = arrayListOf<ExposureSource>().apply {
            arguments?.getParcelable<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE)?.let {
                add(it)
            }
            arguments?.getParcelableArrayList<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)?.let {
                addAll(it)
            }
        }
        // todo transparentBackground的值待定
        val transparentBackground = true
        val pageConfigure =
            PageConfigure(
                customPageId,
                0,
                mEntrance,
                transparentBackground,
                exposureSourceList,
                isInSearchToolbarTabWrapperPage
            )

        val precisePageLevelString = (activity as? IPageLevelProvider)
            ?.getPageLevel()
            ?.getTempNewPageLevel(topTabPosition = tabIndex, bottomTabPosition = bottomTabIndex)
            ?.toFormattedString(ignoreBottomTabPositionMap = true)
            ?: ""

        pageLocation = PageLocation(
            bottomTabName,
            bottomTabIndex,
            precisePageLevelString,
            multiTabNavName,
            multiTabNavId,
            tabIndex,
            tabName,
            customPageName,
            customPageId
        )

        viewModel.init(pageConfigure, searchToolbarTabWrapperViewModel, pageLocation)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = try {
            FragmentCustomBinding.inflate(layoutInflater)
        } catch (e: Exception) {
            SentryHelper.onEvent(
                "VIEW_BINDING_BIND_ERROR",
                "digest", e.localizedMessage,
                "gid", HaloApp.getInstance().gid
            )
            // 玄学，重试一次，该闪退闪退
            FragmentCustomBinding.inflate(layoutInflater)
        }
        mCachedView = binding.root
        return mCachedView
    }

    override fun getRealLayoutId() = R.layout.fragment_custom

    override fun onFragmentFirstVisible() {
        super.onFragmentFirstVisible()
        if (!mIsFromMainWrapper && !mIsFromTabWrapper) {
            initMenu(R.menu.menu_download)
        }
        mainWrapperViewModel?.bottomDoubleTabAction?.observe(viewLifecycleOwner) {
            if (isSupportVisible && it.id == bottomTabId) {
                scrollToTop()
            }
        }

        with(viewModel) {
            customPageData.observe(viewLifecycleOwner, Observer {
                setNavigationTitle(it.title)
            })

            dataList.observe(viewLifecycleOwner) {
                adapter.submitList(it) {
                    if (shouldScrollToTop) {
                        shouldScrollToTop = false
                        binding.gameList.scrollToPosition(0)
                    }
                }
            }

            loadStatus.observe(viewLifecycleOwner) { (status, isPullToRefresh) ->
                binding.gameRefresh.isRefreshing = false

                if (!isPullToRefresh) {
                    binding.gameList.goneIf(status == LoadStatus.INIT_LOADING || status == LoadStatus.INIT_FAILED || status == LoadStatus.INIT_EMPTY)
                    if (status == LoadStatus.INIT_FAILED) {
                        if (noConnectionBinding == null) {
                            binding.reuseNoConnectionStub.setOnInflateListener { _, inflated ->
                                noConnectionBinding = ReuseNoConnectionBinding.bind(inflated)
                                noConnectionBinding?.root?.visibility = View.VISIBLE
                                noConnectionBinding?.connectionReloadTv?.setOnClickListener {
                                    viewModel.loadFirst(false)
                                }
                            }
                            binding.reuseNoConnectionStub.inflateOrShow()
                        } else {
                            noConnectionBinding?.root?.visibility = View.VISIBLE
                        }
                    } else if (status == LoadStatus.INIT_EMPTY) {
                        if (noDataBinding == null) {
                            binding.reuseNoDataStub.setOnInflateListener { _, inflated ->
                                noDataBinding = ReuseNoneDataBinding.bind(inflated)
                                noDataBinding?.root?.visibility = View.VISIBLE
                            }
                            binding.reuseNoDataStub.inflateOrShow()
                        } else {
                            noDataBinding?.root?.visibility = View.VISIBLE
                        }
                    } else {
                        noConnectionBinding?.root?.goneIf(true)
                        noDataBinding?.root?.goneIf(true)
                    }

                    if (status == LoadStatus.INIT_LOADING) {
                        binding.reuseLoading.root.goneIf(false)
                        binding.root.setBackgroundColor(
                            com.gh.gamecenter.common.R.color.ui_surface.toColor(
                                requireContext()
                            )
                        )
                    } else {
                        binding.reuseLoading.root.goneIf(true)
                        binding.root.setBackgroundColor(Color.TRANSPARENT)
                    }
                } else {
                    if (status == LoadStatus.INIT_LOADED) {
                        binding.gameList.visibleIf(true)
                        noConnectionBinding?.root?.goneIf(true)
                        noDataBinding?.root?.goneIf(true)
                    }
                }
                adapter.setLoadStatus(status)
                if (status == LoadStatus.INIT_LOADED) {
                    AppExecutor.uiExecutor.executeWithDelay({
                        scroll()
                        scrollCalculatorHelper.onScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE)
                    }, 100)
                }
                if (status != LoadStatus.INIT_LOADING) {
                    (parentFragment as? ISmartRefresh)?.finishRefresh()
                }
            }

            changAppBarColorAction.observe(viewLifecycleOwner, EventObserver {
                (parentFragment as? ISearchToolbarTab)?.changeAppBarColor(it, customPageId)
            })

            pullDownPushData.observe(viewLifecycleOwner) {
                setSwipeRefreshEnabled(it == null)
                setPullDownPush(it)
            }

            pageSwitchData.observe(viewLifecycleOwner) {
                // 当前自定义页面为二级页面时显示搜索栏
                if (!requireArguments().getBoolean(EntranceConsts.KEY_IS_HOME, false) && it.topSearch.isNotEmpty()) {
                    if (searchBarBinding == null) {
                        binding.reuseSearchBarStub.setOnInflateListener { _, inflated ->
                            searchBarBinding = LayoutSearchBarBinding.bind(inflated)
                            binding.gameRefresh.updateLayoutParams<RelativeLayout.LayoutParams> {
                                addRule(RelativeLayout.BELOW, R.id.reuseSearchBar)
                            }
                            initSearchBar(it)
                        }
                        binding.reuseSearchBarStub.inflateOrShow()
                    } else {
                        initSearchBar(it)
                    }
                }
                // 当前自定义页面为 底部Tab(非多Tab导航页) 关联的页面时更新搜索类型
                if (requireArguments().getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "")
                        .isEmpty() && it.topSearch.isNotEmpty()
                ) {
                    (parentFragment as? ISearchToolbarTab)?.updateSearchStyle(BottomTab.SearchStyle(searchType = it.topSearch))
                }
            }

            gameDetailDestination.observe(viewLifecycleOwner, EventObserver { (entrance, game) ->
                when {
                    game.isDspGame -> {
                        if (game.interactionType == 2) {
                            DspGameDetailDialogFragment.show(requireContext(), game)
                        } else if (game.interactionType == 4) {
                            MiniGameItemHelper.launchMiniGame(game)
                        }
                    }

                    game.isMiniGame() -> {
                        MiniGameItemHelper.launchMiniGame(game)
                    }

                    else -> {
                        GameDetailActivity.startGameDetailActivity(
                            requireContext(),
                            game.id,
                            entrance,
                            traceEvent = game.exposureEvent,
                        )
                    }
                }
            })

            subjectDestination.observe(viewLifecycleOwner, EventObserver { subject ->
                DirectUtils.directToSubject(
                    requireContext(), subject.id ?: "", subject.name, "自定义页面", null, subject.subjectType
                )
            })

            subjectDestinationWithCustom.observe(viewLifecycleOwner, EventObserver { (subject, subjectType) ->
                DirectUtils.directToSubject(
                    requireContext(), subject.id, subject.title, "自定义页面", null, subjectType
                )
            })

            subjectCollectionDestination.observe(viewLifecycleOwner, EventObserver { (item, childPosition, subject) ->
                val clickEvent = if (subject != null) {
                    ExposureEvent.createEventWithSourceConcat(
                        GameEntity(outerSequence = childPosition), pageConfigure.exposureSourceList, listOf(
                            ExposureSource("专题合集", "${item.data.name}+${item.componentStyle}+${item.data.id}"),
                            ExposureSource("专题", "${subject.title}+${subject.styleChinese}+${subject.id}")
                        ), null, ExposureType.CLICK
                    )
                } else null
                clickEvent?.let { ExposureManager.log(it) }
                DirectUtils.directToColumnCollection(
                    requireContext(),
                    item.data.id,
                    childPosition,
                    CustomPageTracker.buildSubjectCollectionEntrance(item),
                    subject?.title ?: "",
                    style = item.data.style,
                    exposureEvent = clickEvent, showSubjectTab = true
                )
            })

            gameListDetailDestination.observe(viewLifecycleOwner, EventObserver { (item, childPosition, subject) ->
                val clickEvent = ExposureEvent.createEventWithSourceConcat(
                    GameEntity(outerSequence = childPosition), pageConfigure.exposureSourceList, listOf(
                        ExposureSource("游戏单合集", "${item.data.name}+${item.componentStyle}+${item.data.id}"),
                        ExposureSource("游戏单", "${subject.title}+${subject.id}")
                    ), null, ExposureType.CLICK
                )
                ExposureManager.log(clickEvent)
                DirectUtils.directToGameCollectionDetail(
                    requireContext(),
                    subject.id,
                    "",
                    "游戏单合集",
                    clickEvent
                )
            })

            userDestination.observe(viewLifecycleOwner, EventObserver { (userId, entrance, path) ->
                DirectUtils.directToHomeActivity(requireContext(), userId, 0, entrance, path)
            })

            interestedGameDestination.observe(viewLifecycleOwner, EventObserver {
                requireContext().startActivity(
                    InterestedGameActivity.getIntent(
                        requireContext(),
                        "${pageConfigure.entrance}-发现页卡片"
                    )
                )

            })

            discoverDestination.observe(viewLifecycleOwner, EventObserver {
                requireContext().startActivity(
                    DiscoveryActivity.getIntent(
                        requireContext(),
                        "${pageConfigure.entrance}-发现页卡片"
                    )
                )
            })

            linkDestination.observe(viewLifecycleOwner, EventObserver { data ->
                DirectUtils.directToLinkPage(requireContext(), data.first, "自定义页面", "", data.second)
            })

            amwayDestination.observe(viewLifecycleOwner, EventObserver {
                DirectUtils.directToAmway(requireContext(), null, "(游戏-专题:安利墙-全部)", "")
            })

            badgeWallDestination.observe(viewLifecycleOwner, EventObserver {
                DirectUtils.directToBadgeWall(
                    requireContext(),
                    it.user.id,
                    it.user.name,
                    it.user.icon
                )
            })

            gameDetailDestinationOnAmway.observe(
                viewLifecycleOwner,
                EventObserver { (gameId, exposureEvent) ->
                    GameDetailActivity.startGameDetailActivity(
                        requireContext(),
                        gameId = gameId,
                        entrance = "自定义页面",
                        traceEvent = exposureEvent,
                    )
                })

            ratingReplyDestination.observe(viewLifecycleOwner, EventObserver { (gameId, commentId) ->
                val entrance = "安利墙"
                val exposureSource =
                    arrayListOf(
                        ExposureSource("自定义页面", "${pageLocation.pageName}+${pageLocation.pageId}"),
                        ExposureSource("安利墙")
                    ).toJson()
                val intent = RatingReplyActivity.getIntent(
                    context = requireContext(),
                    gameId = gameId,
                    commentId = commentId,
                    showKeyboardIfReplyListIsEmpty = false,
                    exposureSource = exposureSource,
                    entrance = entrance,
                    path = ""
                )
                requireContext().startActivity(intent)
            })

            commonCollectionDestination.observe(viewLifecycleOwner, EventObserver { (commonCollection, collectionId) ->
                val intent = CustomCommonCollectionDetailActivity.getIntent(
                    requireContext(),
                    collectionId,
                    commonCollection.layout,
                    "自定义页面",
                )
                startActivity(intent)
            })

            gameListCollectionDestination.observe(viewLifecycleOwner, EventObserver {
                DirectUtils.directToGameCollectionListDetail(
                    requireContext(),
                    it.data.id,
                    it.data.name,
                    it.data.explain,
                    "自定义页面"
                )
            })

            gameListSquareDestination.observe(viewLifecycleOwner, EventObserver {
                DirectUtils.directToGameCollectionSquare(
                    requireContext(),
                    "版块内容列表",
                    "",
                    collectionName = it.data.name,
                    collectionId = it.data.id
                )
            })
        }

        searchToolbarTabWrapperViewModel?.backgroundAlpha?.observe(viewLifecycleOwner) {
            val viewHolder = binding.gameList.findViewHolderForAdapterPosition(0)
            if (viewHolder is OnCustomPageRefreshStateListener) {
                viewHolder.onBackgroundAlphaChanged(it)
            }
        }

        SensorsBridge.trackViewCustomPage(
            pageLocation.bottomTab,
            pageLocation.severalTabPageId,
            pageLocation.severalTabPageName,
            pageLocation.tabPosition,
            pageLocation.tabContent,
            pageLocation.pageId,
            pageLocation.pageName,
            mEntrance
        )

        viewModel.loadData()
    }

    private fun setSearchHint(searchType: String) {
        if (searchBarBinding == null) return

        when (searchType) {
            BottomTab.SearchStyle.TYPE_HALO_GAME -> DefaultSearchHintHelper.setSearchHint(searchBarBinding!!.searchTv)
            BottomTab.SearchStyle.TYPE_MINI_GAME -> searchBarBinding!!.searchTv.hint = "请输入小游戏关键词"
            BottomTab.SearchStyle.TYPE_BBS -> searchBarBinding!!.searchTv.hint = "搜索论坛内容、用户"
        }
    }

    override fun initRealView() {
        super.initRealView()

        scrollCalculatorHelper = ScrollCalculatorHelper(binding.gameList, R.id.autoVideoView, 0, false)

        buildPriorityChain()

        adapter = CustomPageAdapter(
            viewModel,
            viewLifecycleOwner,
            scrollCalculatorHelper,
        )
        layoutManager = ScrollableLinearLayoutManager(requireContext())
        binding.gameList.itemAnimator = null
        binding.gameList.layoutManager = layoutManager
        binding.gameList.adapter = adapter
        binding.gameList.addExposureHelper(this, DefaultExposureStateChangeListener())

        var listScrollHeight = 0
        binding.gameList.addOnScrollListener(object : OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                floatViewManager.onScrollChanged(newState != RecyclerView.SCROLL_STATE_IDLE)
                scrollCalculatorHelper.onScrollStateChanged(newState)
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                listScrollHeight += dy
                onScrollChanged()
                scroll()
            }
        })

        binding.gameRefresh.setOnRefreshListener {
            onRefresh()
        }
    }

    private fun initSearchBar(switch: CustomPageData.PageSwitch) {
        searchBarBinding?.root?.setPadding(16F.dip2px(), 8F.dip2px(), 16F.dip2px(), 8F.dip2px())

        searchBarBinding?.root?.visibility = View.VISIBLE
        searchBarBinding?.etSearch?.visibility = View.GONE
        searchBarBinding?.searchTv?.visibility = View.VISIBLE
        setSearchHint(switch.topSearch)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            searchBarBinding?.etSearch?.focusable = View.NOT_FOCUSABLE
        }
        listOf(searchBarBinding?.root, searchBarBinding?.searchTv).forEach { view ->
            view?.setOnClickListener { _ ->
                DirectUtils.directToSearch(
                    requireContext(),
                    switch.topSearch,
                    searchBarBinding?.searchTv?.hint.toString(),
                    "搜索栏",
                    "自定义页面",
                    bottomTabName,
                    customPageId = customPageId,
                    customPageName = customPageName
                )
            }
        }
    }

    private fun buildPriorityChain() {
        val videoHandler = VideoHandler(24, scrollCalculatorHelper)

        if (showPullDownPush) {
            priorityChain.addHandler(pullDownPushHandler)
        }

        if (showFloatingWindow) {
            val floatingWindowHandler = CustomFloatingWindowHandler(23)
            priorityChain.addHandler(floatingWindowHandler)

            viewModel.floatingWindows.observe(viewLifecycleOwner, EventObserver {
                floatingWindowHandler.setData(it)
            })

            floatingWindowHandler.showFloatingAction.observe(viewLifecycleOwner, EventObserver {
                binding.floatingView.setData(
                    it,
                    pageLocation,
                    viewModel.pageConfigure.exposureSourceList,
                    floatingWindowHandler
                )
                floatViewManager.show(binding.floatingView)
            })

            binding.floatingView.setExpandListener { entity, hasAnimation ->
                val dialog = CustomWelcomeDialogFragment.getInstance(entity, true, this, hasAnimation, pageLocation)
                dialog.setDismissListener {
                    floatViewManager.resume()
                    floatingWindowHandler.dismiss()
                }
                dialog.show(childFragmentManager, CustomWelcomeDialogFragment.TAG)
            }
        }

        priorityChain.addHandler(videoHandler)
        (parentFragment as? BaseTabWrapperFragment)?.addTabGuideHandlerIfExists(priorityChain)

        if (superiorChain != null) {
            superiorChain?.registerInferiorChain(priorityChain)
        } else {
            priorityChain.start()
        }
    }

    private fun onScrollChanged(isDarkModeChanged: Boolean = false) {
        if (parentFragment is ISearchToolbarTab &&
            (tabIndex == (parentFragment as ISearchToolbarTab).getCurrentTabIndex() || tabIndex == -1) &&
            ::layoutManager.isInitialized
        ) {
            val bannerViewHeight = layoutManager.findViewByPosition(0)?.height ?: 0
            (parentFragment as ISearchToolbarTab).onScrollChanged(
                bannerViewHeight,
                binding.gameList.computeVerticalScrollOffset(),
                isDarkModeChanged
            )
        }
    }

    private fun scroll() {
        val firstVisibleItem = layoutManager.findFirstVisibleItemPosition()
        val lastVisibleItem = layoutManager.findLastVisibleItemPosition()
        scrollCalculatorHelper.onScroll(firstVisibleItem, lastVisibleItem)
    }

    override fun onFragmentPause() {
        super.onFragmentPause()
        pauseVideo()

        if (::adapter.isInitialized) {
            DownloadManager.getInstance().removeObserver(dataWatcher)
        }

        superiorChain?.unregisterInferiorChain(priorityChain)
        GlobalActivityManager.updatePageBusinessId(requireActivity())
    }

    override fun onFragmentResume() {
        super.onFragmentResume()
        resumeVideo()
        if (::adapter.isInitialized) {
            DownloadManager.getInstance().addObserver(dataWatcher)
        }
        viewModel.pullDownPushData.value?.let { setPullDownPush(it) }

        superiorChain?.registerInferiorChain(priorityChain)

        GlobalActivityManager.updatePageBusinessId(requireActivity())
    }

    private fun setPullDownPush(pullDownPush: PullDownPush?) {
        (parentFragment as? ISmartRefresh)?.setPullDownPush(pullDownPush, pullDownPushHandler)
    }

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

    //下载被删除事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(status: EBDownloadStatus) {
        if (::adapter.isInitialized && "delete" == status.status) {
            adapter.notifyDownloadDeleted(status)
        }
    }

    //安装、卸载事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(busFour: EBPackage) {
        if (::adapter.isInitialized) {
            adapter.notifyInstalled(busFour)
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(reuse: EBReuse) {
        if (::adapter.isInitialized && "Refresh" == reuse.type) {
            setSearchHint(viewModel.pageSwitchData.value?.topSearch ?: "")
            adapter.notifyDataSetChanged()
        }
    }

    fun setSuperiorChain(superiorChain: ISuperiorChain?): CustomPageFragment {
        this.superiorChain = superiorChain
        return this
    }

    private fun pauseVideo() {
        val currentPlayer = scrollCalculatorHelper.currentPlayer
        if (currentPlayer != null) {
            currentPlayer.resetDetailMask()
            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 (position != 0L) {
                        scrollCalculatorHelper.currentPlayer?.seekTo(position)
                        scrollCalculatorHelper.currentPlayer?.onVideoResume(false)
                        val topVideoVoiceStatus = SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true)
                        if (topVideoVoiceStatus) {
                            scrollCalculatorHelper.currentPlayer?.mute()
                        } else {
                            scrollCalculatorHelper.currentPlayer?.unMute()
                        }
                    } else {
                        scrollCalculatorHelper.currentPlayer?.release()
                    }

                }, 50)
            }
        }
    }

    fun showUnzipFailureDialog(downloadEntity: DownloadEntity) {
        val data = adapter.getGameEntityByPackage(downloadEntity.packageName)
        for (gameAndPosition in data) {
            val targetView = layoutManager.findViewByPosition(gameAndPosition.position)
            if (targetView != null) {
                if (targetView is RecyclerView) {
                    // todo 如果时竖向专题该怎么判断?
                } else {
                    DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
                    return
                }
            }
        }
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        if (::adapter.isInitialized && ::binding.isInitialized) {
            binding.gameList.tryToClearRecycler()
            binding.gameList.recycledViewPool.clear()

            adapter.notifyItemRangeChanged(0, adapter.itemCount)
            binding.gameList.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
            searchBarBinding?.searchTv?.setHintTextColor(
                com.gh.gamecenter.common.R.color.text_instance.toColor(
                    requireContext()
                )
            )
            onScrollChanged(true)
        }
    }

    private fun setScrollEnabled(isScrollEnabled: Boolean) {
        if (::layoutManager.isInitialized) {
            layoutManager.isScrollVerticallyEnabled = isScrollEnabled
        }
    }

    override fun onRefresh() {
        viewModel.onRefresh()
    }

    override fun setSwipeRefreshEnabled(isSwipeRefreshEnabled: Boolean) {
        if (::binding.isInitialized) {
            binding.gameRefresh.isEnabled = isSwipeRefreshEnabled
        }
    }

    override fun onStateChanged(refreshLayout: RefreshLayout, oldState: RefreshState, newState: RefreshState) {
        if (oldState == RefreshState.None && newState == RefreshState.PullDownToRefresh) {
            pauseVideo()
        } else if ((oldState == RefreshState.TwoLevelFinish || oldState == RefreshState.RefreshFinish) && newState == RefreshState.None) {
            val currentPlayer = scrollCalculatorHelper.currentPlayer
            if (currentPlayer == null) {
                scrollCalculatorHelper.playIfValid()
            } else if (currentPlayer.currentState == GSYVideoView.CURRENT_STATE_PAUSE) {
                resumeVideo()
            }
        }

        when (newState) {
            RefreshState.TwoLevel -> {
                setScrollEnabled(false)
            }

            RefreshState.None -> {
                setScrollEnabled(true)
            }

            else -> {
                // do nothing
            }
        }
    }

    override fun scrollToTop() {
        if (::binding.isInitialized) {
            binding.gameList.stopScroll()
            binding.gameList.scrollToPosition(0)
        }
    }

    fun getFloatingViewY(): Int = if (::binding.isInitialized) {
        val locations = IntArray(2)
        binding.floatingView.getLocationInWindow(locations)
        locations[1]
    } else {
        0
    }

    override fun getBusinessId(): Pair<String, String> = Pair(customPageId, "")

}