package com.gh.gamecenter.home

import android.view.View
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.databind.BindingAdapters
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.DialogUtils
import com.gh.common.xapk.XapkInstaller
import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
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.eventbus.EBReuse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.OffsetLinearLayoutManager
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.FragmentMainHomeBinding
import com.gh.gamecenter.eventbus.EBDiscoverChanged
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.eventbus.EBUISwitch
import com.gh.gamecenter.fragment.HomeSearchToolWrapperFragment
import com.gh.gamecenter.fragment.HomeSearchToolWrapperViewModel
import com.gh.gamecenter.fragment.MainWrapperFragment
import com.gh.gamecenter.game.gallery.GameGallerySlideViewHolder
import com.gh.gamecenter.home.slide.HomeSlideListAdapter
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode

class HomeFragment : LazyFragment() {

    private lateinit var mViewModel: HomeViewModel
    private lateinit var mHomeSearchViewModel: HomeSearchToolWrapperViewModel
    private lateinit var mBinding: FragmentMainHomeBinding
    private lateinit var mLayoutManager: LinearLayoutManager
    private lateinit var mListAdapter: HomeFragmentAdapter

    private lateinit var mExposureListener: ExposureListener
    private lateinit var mScrollCalculatorHelper: ScrollCalculatorHelper
    private lateinit var mAutomaticLayoutManager: OffsetLinearLayoutManager

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

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

        override fun onDataInit(downloadEntity: DownloadEntity) {
            mListAdapter.notifyItemByDownload(downloadEntity)
        }
    }

    override fun getRealLayoutId() = R.layout.fragment_main_home

    override fun onFragmentFirstVisible() {
        mViewModel = viewModelProvider()
        mHomeSearchViewModel = viewModelProviderFromParent()
        mViewModel.homeOnlyWithoutOtherTab = arguments?.getInt(EntranceConsts.KEY_TAB_COUNT) == 1
        super.onFragmentFirstVisible()

        mViewModel.itemDataList.observeNonNull(this, callback = {
            mListAdapter.submitList(it)
        })
        mViewModel.loadStatus.observeNonNull(this, callback = {
            val loadStatus = it
            mBinding.run {
                BindingAdapters.isRefreshing(gameRefresh, LoadStatus.LIST_LOADED)
                gameRefresh.goneIf(loadStatus == LoadStatus.INIT_FAILED)
                gameList.goneIf(loadStatus == LoadStatus.INIT_LOADING)
                reuseNoConnection.root.goneIf(loadStatus != LoadStatus.INIT_FAILED)
                reuseLoading.root.goneIf(loadStatus != LoadStatus.INIT_LOADING)
            }
            mListAdapter.setLoadStatus(it)
            if (it == LoadStatus.INIT_LOADED) {
                AppExecutor.uiExecutor.executeWithDelay({
                    scroll()
                    mScrollCalculatorHelper.onScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE)
                }, 100)
            }
        })
        mHomeSearchViewModel.homeDataLiveData.observe(this) {
            mViewModel.initData(it)
        }

        mScrollCalculatorHelper = ScrollCalculatorHelper(mBinding.gameList, R.id.autoVideoView, 0)
    }

    override fun onRealLayoutInflated(inflatedView: View) {
        super.onRealLayoutInflated(inflatedView)

        mBinding = FragmentMainHomeBinding.bind(inflatedView)
        mBinding.gameRefresh.setColorSchemeColors(
            ContextCompat.getColor(
                requireContext(),
                R.color.theme
            )
        )
        mBinding.run {
            BindingAdapters.isRefreshing(gameRefresh, LoadStatus.LIST_LOADED)
        }
        mAutomaticLayoutManager = OffsetLinearLayoutManager(requireContext())
        mLayoutManager = mAutomaticLayoutManager
        mListAdapter = HomeFragmentAdapter(requireContext(), mViewModel, mLayoutManager) {
            if (parentFragment is HomeSearchToolWrapperFragment) {
                (parentFragment as HomeSearchToolWrapperFragment).changeAppBarColor(it)
            }
        }
        mExposureListener = ExposureListener(this, mListAdapter)
        (mBinding.gameList.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
        mBinding.gameList.layoutManager = mLayoutManager
        mBinding.gameList.adapter = mListAdapter

        mBinding.gameList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                mScrollCalculatorHelper.onScrollStateChanged(newState)
                if (mLayoutManager.findLastVisibleItemPosition() == mListAdapter.itemCount - 1
                    && RecyclerView.SCROLL_STATE_IDLE == newState
                ) mViewModel.getHomeContent(false)
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (parentFragment is HomeSearchToolWrapperFragment) {
                    val bannerViewHeight = mAutomaticLayoutManager.heightMap[0] ?: 0
                    val type = (parentFragment as HomeSearchToolWrapperFragment).getCurrentTab()?.type
                    if (type == "home") {
                        (parentFragment as HomeSearchToolWrapperFragment).onScrollChanged(
                            bannerViewHeight,
                            mBinding.gameList.computeVerticalScrollOffset()
                        )
                    }
                }
                scroll()
            }
        })
        mBinding.gameList.addOnScrollListener(mExposureListener)

        mBinding.gameRefresh.setOnRefreshListener {
            MtaHelper.onEvent("首页_新", "刷新")
            mViewModel.loadStatus.postValue(LoadStatus.LIST_LOADING)
            mHomeSearchViewModel.getHomeContentUnion(true)
        }

        mBinding.reuseNoConnection.root.setOnClickListener {
            mViewModel.loadStatus.postValue(LoadStatus.INIT_LOADING)
            mHomeSearchViewModel.getHomeContentUnion(true)
        }
    }

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

    override fun onFragmentPause() {
        pauseVideo()

        DownloadManager.getInstance().removeObserver(dataWatcher)

        handleAutoScroll(false)
    }

    override fun onFragmentResume() {
        resumeVideo()

        DownloadManager.getInstance().addObserver(dataWatcher)

        handleAutoScroll(true)
    }

    private fun pauseVideo() {
        if (mScrollCalculatorHelper.currentPosition >= 0) {
            mScrollCalculatorHelper.currentPlayer?.resetDetailMask()
            mScrollCalculatorHelper.currentPlayer?.onVideoPause()
            val currentPosition = mScrollCalculatorHelper.currentPlayer?.getCurrentPosition() ?: 0L
            val topVideo =
                mViewModel.itemDataList.value?.safelyGetInRelease(mScrollCalculatorHelper.currentPosition)?.attachGame?.linkGame?.topVideo
            if (topVideo != null) {
                ScrollCalculatorHelper.savePlaySchedule(
                    MD5Utils.getContentMD5(topVideo.url),
                    currentPosition
                )
            }
        }
    }

    private fun resumeVideo() {
        if (mScrollCalculatorHelper.currentPlayer != null) {
            val topVideo =
                mViewModel.itemDataList.value?.safelyGetInRelease(mScrollCalculatorHelper.currentPosition)?.attachGame?.linkGame?.topVideo
            if (topVideo != null) {
                val position =
                    ScrollCalculatorHelper.getPlaySchedule(MD5Utils.getContentMD5(topVideo.url))
                //这里必须要延迟操作，否则会白屏
                mBaseHandler.postDelayed({
                    if (position != 0L) {
                        mScrollCalculatorHelper.currentPlayer?.seekTo(position)
                        mScrollCalculatorHelper.currentPlayer?.onVideoResume(false)
                        val topVideoVoiceStatus =
                            SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true)
                        if (topVideoVoiceStatus) {
                            mScrollCalculatorHelper.currentPlayer?.mute()
                        } else {
                            mScrollCalculatorHelper.currentPlayer?.unMute()
                        }
                    } else {
                        mScrollCalculatorHelper.currentPlayer?.release()
                    }

                }, 50)
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (::mScrollCalculatorHelper.isInitialized) {
            mScrollCalculatorHelper.currentPlayer?.release()
        }
    }

    private fun handleAutoScroll(resumeScroll: Boolean) {
        val view = mBinding.gameList.layoutManager?.findViewByPosition(0)
        val recyclerView = view?.findViewById<RecyclerView>(R.id.recycler_view)
        val adapter = recyclerView?.adapter
        if (adapter is HomeSlideListAdapter) {
            if (resumeScroll) adapter.startScroll() else adapter.stopScroll()
        }

        val firstPosition =
            (mBinding.gameList.layoutManager as? LinearLayoutManager)?.findFirstVisibleItemPosition()
                ?: 0
        val lastPosition =
            (mBinding.gameList.layoutManager as? LinearLayoutManager)?.findLastVisibleItemPosition()
                ?: 0

        for (i in firstPosition..lastPosition) {
            val viewHolder = mBinding.gameList.findViewHolderForAdapterPosition(i)
            if (viewHolder is GameGallerySlideViewHolder) {
                if (resumeScroll) viewHolder.resumeScrolling() else viewHolder.pauseScrolling()
            }
        }
    }

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

    //安装、卸载事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(busFour: EBPackage) {
        val data = mListAdapter.getGameEntityByPackage(busFour.packageName)
        for (gameAndPosition in data) {
            mListAdapter.notifyChildItem(gameAndPosition.position, busFour.packageName)
        }
        mViewModel.refreshRecentVGameIfNeeded()
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(reuse: EBReuse) {
        if (::mListAdapter.isInitialized && "Refresh" == reuse.type) {
            mListAdapter.notifyDataSetChanged()
        }
        mViewModel.refreshRecentVGameIfNeeded()
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(busNine: EBUISwitch) {
        if (::mLayoutManager.isInitialized
            && MainWrapperFragment.EB_MAIN_SCROLL_TOP == busNine.from
            && MainWrapperFragment.INDEX_HOME == busNine.position
        ) {
            mBinding.gameList.stopScroll()
            mLayoutManager.scrollToPosition(0)
            mScrollCalculatorHelper.currentPlayer?.release()
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(changed: EBDiscoverChanged) {
        mViewModel.refreshDiscoverCardData()
    }

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

    fun onScrollChanged() {
        if (parentFragment is HomeSearchToolWrapperFragment && ::mAutomaticLayoutManager.isInitialized) {
            val bannerViewHeight = mAutomaticLayoutManager.heightMap[0] ?: 0
            (parentFragment as HomeSearchToolWrapperFragment).onScrollChanged(
                bannerViewHeight,
                mBinding.gameList.computeVerticalScrollOffset()
            )
        }
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        if (::mBinding.isInitialized) {
            mBinding.gameList.recycledViewPool.clear()
            if (::mListAdapter.isInitialized) mListAdapter.notifyItemRangeChanged(0, mListAdapter.itemCount)
            if (isSupportVisible) {
                onScrollChanged()
            }
            val view = mBinding.gameList.layoutManager?.findViewByPosition(0)
            val recyclerView = view?.findViewById<RecyclerView>(R.id.recycler_view)
            val adapter = recyclerView?.adapter
            if (adapter is HomeSlideListAdapter) {
                adapter.notifyItemRangeChanged(0, adapter.itemCount)
            }
        }
    }
}