package com.gh.gamecenter.game

import android.graphics.Color
import android.view.View
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.ethanhua.skeleton.Skeleton
import com.ethanhua.skeleton.ViewSkeletonScreen
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.FixLinearLayoutManager
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.FragmentGameBinding
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.feature.exposure.ExposureSource
import com.gh.gamecenter.fragment.MainWrapperFragment
import com.gh.gamecenter.game.data.GameItemData
import com.gh.gamecenter.home.test_v2.HomeGameTestV2ViewModel
import com.gh.gamecenter.home.test_v2.HomeItemGameTestV2ViewHolder
import com.gh.gamecenter.home.test_v2.HomeItemGameTestV2ViewHolderWatcher
import com.gh.gamecenter.home.test_v2.addViewHolderWatcher
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode

class GameFragment : LazyFragment() {

    private lateinit var mViewModel: GameViewModel
    private lateinit var mHomeGameTestV2ViewModel: HomeGameTestV2ViewModel

    private lateinit var mBinding: FragmentGameBinding
    private lateinit var mSkeleton: ViewSkeletonScreen
    private lateinit var mListAdapter: GameFragmentAdapter
    private lateinit var mLayoutManager: LinearLayoutManager

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

    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_game

    override fun onFragmentFirstVisible() {
        val factory = GameViewModel.Factory(
            HaloApp.getInstance().application,
            arguments?.getParcelable(EntranceConsts.KEY_BLOCK_DATA)
        )
        mViewModel = ViewModelProviders.of(this, factory).get(GameViewModel::class.java)
        mViewModel.entrance = mEntrance
        //新游开测模块
        mHomeGameTestV2ViewModel = viewModelProvider()
        mHomeGameTestV2ViewModel.location = "板块"
        mHomeGameTestV2ViewModel.blockData = mViewModel.blockData
        mViewModel.setHomeGameTestV2DownloadStateUpdateHelper(mHomeGameTestV2ViewModel)

        super.onFragmentFirstVisible()

        mViewModel.loadStatus.observe(this) {
            if (it != null) {
                mBinding.gameRefresh.isRefreshing = false
                mBinding.gameRefresh.goneIf(it == LoadStatus.INIT_FAILED)
                mBinding.gameList.goneIf(it == LoadStatus.INIT_LOADING)
                mBinding.reuseNoConnection.root.goneIf(it != LoadStatus.INIT_FAILED)

                mListAdapter.setLoadStatus(it)
                mBinding.reuseNoConnection.root.visibility =
                    if (it == LoadStatus.INIT_FAILED) View.VISIBLE else View.GONE
                if (it != LoadStatus.INIT_LOADING) {
                    mBinding.root.setBackgroundColor(Color.TRANSPARENT)
                    mSkeleton.hide()
                } else {
                    mBinding.root.setBackgroundColor(R.color.background_white.toColor(requireContext()))
                    mSkeleton.show()
                    mViewModel.resetOffset()
                }
                if (it != LoadStatus.INIT_LOADED) {
                    AppExecutor.uiExecutor.executeWithDelay({
                        scroll()
                        mScrollCalculatorHelper.onScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE)
                    }, 100)
                }
            }
        }
        mViewModel.itemDataList.observe(this, Observer {
            if (it != null) mListAdapter.setItemDataList(it as MutableList<GameItemData>)
        })
        mViewModel.commandScrollTop.observe(this, Observer {
            mBinding.gameList.scrollToPosition(0)
        })

        setNavigationTitle(mViewModel.blockData?.text)
    }

    override fun initRealView() {
        super.initRealView()

        mBinding = FragmentGameBinding.bind(mCachedView)
        mScrollCalculatorHelper = ScrollCalculatorHelper(mBinding.gameList, R.id.autoVideoView, 0)
        mBinding.gameRefresh.setColorSchemeColors(ContextCompat.getColor(requireContext(), R.color.theme))
        mLayoutManager = FixLinearLayoutManager(context)
        val exposureSourceList = arrayListOf<ExposureSource>().apply {
            arguments?.getParcelable<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE)?.let {
                add(it)
            }
            add(
                ExposureSource(
                    "板块",
                    if (mViewModel.blockData?.text.isNullOrEmpty()) "" else mViewModel.blockData?.text!!
                )
            )
        }
        mListAdapter = GameFragmentAdapter(
            requireContext(),
            mViewModel,
            this,
            mHomeGameTestV2ViewModel = mHomeGameTestV2ViewModel,
            exposureSourceList,
            mLayoutManager,
            mScrollCalculatorHelper
        )

        mBinding.gameList.run {
            (itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
            layoutManager = mLayoutManager
            adapter = mListAdapter
        }

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

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                listScrollHeight += dy
                mBinding.replaceDataButton.visibleIf(mViewModel.blockData?.display?.refresh == true && listScrollHeight > 100F.dip2px())
                scroll()
            }
        })

        //监听新游开测条目可见性变化
        mBinding.gameList.addViewHolderWatcher(
            HomeItemGameTestV2ViewHolder::class.java,
            HomeItemGameTestV2ViewHolderWatcher()
        )

        mExposureListener = ExposureListener(this, mListAdapter)
        mBinding.gameList.addOnScrollListener(mExposureListener)

        mBinding.gameRefresh.setOnRefreshListener {
            mViewModel.loadStatus.value = LoadStatus.INIT
            mViewModel.initData()
        }

        mBinding.reuseNoConnection.root.setOnClickListener { mViewModel.initData() }
        mBinding.replaceDataButton.setOnClickListener {
            val firstVisiblePosition = mLayoutManager.findFirstVisibleItemPosition()
            val lastVisiblePosition = mLayoutManager.findLastVisibleItemPosition()
            if (firstVisiblePosition == RecyclerView.NO_POSITION
                || lastVisiblePosition == RecyclerView.NO_POSITION
            ) return@setOnClickListener

            for (position in firstVisiblePosition..lastVisiblePosition) {
                val itemData = mListAdapter.getItemDataByPosition(position)
                if (itemData != null && mViewModel.replaceRefreshData(itemData)) mListAdapter.notifyItemChanged(position)
            }
        }

        mBinding.root.setBackgroundColor(Color.WHITE)
        mSkeleton = Skeleton.bind(mBinding.gameSkeletonContainer)
            .shimmer(true)
            .angle(Constants.SHIMMER_ANGLE)
            .color(R.color.skeleton_shimmer_color)
            .duration(Constants.SHIMMER_DURATION)
            .maskWidth(Constants.MASK_WIDTH)
            .gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
            .maskWidth(Constants.MASK_WIDTH)
            .gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
            .apply {
                if (mViewModel.isGameRepo()) {
                    load(R.layout.fragment_game_repo_skeleton)
                } else {
                    load(R.layout.fragment_game_skeleton)
                }
            }
            .show()
    }

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

    override fun onFragmentPause() {
        super.onFragmentPause()
        pauseVideo()
        DownloadManager.getInstance().removeObserver(dataWatcher)
        if (::mListAdapter.isInitialized) {
            mListAdapter.isAutoScroll = false
            mListAdapter.notifyFirstItem()
        }
    }

    override fun onFragmentResume() {
        super.onFragmentResume()
        resumeVideo()
        if (::mListAdapter.isInitialized) {
            DownloadManager.getInstance().addObserver(dataWatcher)
            mListAdapter.isAutoScroll = true
            mListAdapter.notifyFirstItem()
        }
    }

    private fun pauseVideo() {
        val currentPlayer = mScrollCalculatorHelper.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 = mScrollCalculatorHelper.currentPlayer
        if (currentPlayer != null) {
            val videoUrl = currentPlayer.getUrl()
            if (videoUrl.isNotEmpty()) {
                val position = ScrollCalculatorHelper.getPlaySchedule(MD5Utils.getContentMD5(videoUrl))
                //这里必须要延迟操作，否则会白屏
                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.release()
        }
    }

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

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

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

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

    @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
                }
            }
        }
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        if (::mListAdapter.isInitialized && ::mBinding.isInitialized) {
            mListAdapter.notifyItemRangeChanged(0, mListAdapter.itemCount)
            mBinding.gameList.setBackgroundColor(R.color.background_white.toColor(requireContext()))
        }
    }
}