package com.gh.gamecenter.gamedetail.desc

import android.app.Activity
import android.content.Intent
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.alibaba.android.arouter.launcher.ARouter
import com.gh.common.util.DirectUtils
import com.gh.common.util.OnSyncCallBack
import com.gh.common.util.SyncDataBetweenPageHelper
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.constant.RouteConsts
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.provider.IFloatingWindowProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.FragmentDescBinding
import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.eventbus.EBScroll
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.GameDetailFragment.Companion.SKIP_DESC
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.entity.DetailEntity
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity
import com.gh.gamecenter.gamedetail.rating.RatingFragment
import com.gh.gamecenter.video.detail.VideoDetailActivity
import com.halo.assistant.HaloApp
import io.reactivex.disposables.CompositeDisposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode

// TODO 处理页面重建时会生成额外 Fragment 的问题
class DescFragment: LazyFragment(), IScrollable {

    private var mAdapter: DescAdapter ? = null
    private var mLayoutManager: LinearLayoutManager? = null
    private var mGameEntity: GameEntity? = null

    private var mNewDetailEntity: NewGameDetailEntity? = null

    private lateinit var mViewModel: DescViewModel
    private lateinit var mBinding: FragmentDescBinding

    private var mCompositeDisposable = CompositeDisposable()

    var openVideoStreaming = false // 是否自动打开视频流

    private var mScrollToLibao = false
    private var mScrollToServer = false

    override fun getRealLayoutId() = R.layout.fragment_desc

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        val adapter = mAdapter ?: return

        if (resultCode == Activity.RESULT_OK) {
            if (DescCommentsAdapter.RATING_REPLY_REQUEST == requestCode || DescCommentsAdapter.RATING_PATCH_REQUEST == requestCode) {
                var commentPosition = 0
                SyncDataBetweenPageHelper.resultHandle(data, object : OnSyncCallBack<RatingComment> {
                    override fun onData(dataPosition: Int): RatingComment? {
                        val descItemList = adapter.descItemList
                        for (i in 0 until descItemList.size) {
                            val comments = descItemList[i].comment
                            if (comments != null) {
                                commentPosition = i
                                val ratingComment = comments[dataPosition]
                                if (DescCommentsAdapter.RATING_PATCH_REQUEST == requestCode) {
                                    ratingComment.ignore = mGameEntity?.ignoreComment ?: false
                                }
                                return ratingComment
                            }
                        }
                        return null
                    }

                    override fun onNotify(dataPosition: Int) {
                        adapter.notifyItemChanged(commentPosition)
                    }
                })
            } else if (requestCode == 100) {
                val position = adapter.descItemList.indexOfFirst { it.type == DetailEntity.Type.LIBAO.value }
                adapter.notifyItemChanged(position)
            }
        } else if (requestCode == DescCommentsAdapter.RATING_REPLY_REQUEST && resultCode == RatingFragment.RATING_DELETE_RESULT) {
            data?.getParcelableExtra<RatingComment>(RatingComment::class.java.simpleName)?.run {
                val descItemList = adapter.descItemList
                var commentPosition = 0
                for (i in 0 until descItemList.size) {
                    val comments = descItemList[i].comment
                    if (comments != null) {
                        commentPosition = i
                        val deleteCommentPosition = comments.indexOfFirst { it.id == id }
                        if (deleteCommentPosition != -1) comments.removeAt(deleteCommentPosition)
                        break
                    }
                }
                adapter.notifyItemChanged(commentPosition)
            }
        }
    }

    override fun onFragmentFirstVisible() {
        mGameEntity = arguments?.getParcelable(GameEntity.TAG)
        openVideoStreaming = arguments?.getBoolean(EntranceConsts.KEY_OPEN_VIDEO_STREAMING, false) ?: false
        mScrollToLibao = arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO, false) ?: false
        mScrollToServer = arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_SERVER, false) ?: false

        val gameDetailFactory =
            GameDetailViewModel.Factory(HaloApp.getInstance().application, mGameEntity?.id, mGameEntity)
        val gameDetailViewModel: GameDetailViewModel = viewModelProviderFromParent(gameDetailFactory)
        mNewDetailEntity = gameDetailViewModel.gameDetailLiveData.value?.data

        val factory = DescViewModel.Factory(HaloApp.getInstance().application, mGameEntity)
        mViewModel = viewModelProvider(factory)

        super.onFragmentFirstVisible()

        gameDetailViewModel.gameDetailLiveData.observeNonNull(this) { gameDetail ->
            if (gameDetail.data == null) return@observeNonNull

            mAdapter?.updateDescItemList(mViewModel.decorateList(gameDetail.data!!.detailEntity))
            // 非镜像游戏获取大家都在玩 (数据来源看具体方法内容) 数据
            if (mGameEntity?.shouldUseMirrorInfo() == false) {
                mViewModel.generateRecommendedGamesItem(gameDetail.data!!.detailEntity)
            }
            if (openVideoStreaming) {
                gameDetail.data!!.detailEntity.forEach { entity ->
                    if (entity.video != null && activity !is VideoDetailActivity) {
                        DirectUtils.directToVideoDetail(
                            requireContext(), entity.video!![0].videoId, entity.video!![0].videoId, path = "游戏详情-介绍视频"
                        )
                        return@forEach
                    }
                }
            }
        }
        gameDetailViewModel.unifiedGameDetailWithUserRelatedInfoForChildLiveData.observeNonNull(this) {
            mAdapter?.updateDescItemList(mViewModel.decorateList(it.detailEntity))
        }
        mViewModel.list.observe(this) {
            mAdapter?.updateDescItemList(it)
            if (mScrollToLibao && mViewModel.getLibaoIndexPosition() != -1) {
                mScrollToLibao = false
                mLayoutManager?.scrollToPositionWithOffset(mViewModel.getLibaoIndexPosition(), 0)
            }
            if (mScrollToServer && mViewModel.getServerIndexPosition() != -1) {
                mScrollToServer = false
                mLayoutManager?.scrollToPositionWithOffset(mViewModel.getServerIndexPosition(), 0)
            }
        }

        mViewModel.changeColumnGameLiveData.observe(this) {
            val viewHolder =
                mBinding.recyclerview.findViewHolderForAdapterPosition(mViewModel.getColumnRecommendPosition()) as? DescAdapter.ColumnRecommendViewHolder
            viewHolder?.binding?.run {
                headPb.visibility = View.GONE
                moreTv.isEnabled = true
            }
            if (it) {
                mAdapter?.notifyItemChanged(mViewModel.getColumnRecommendPosition())
            }
        }
    }

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

        mBinding = FragmentDescBinding.bind(inflatedView)

        showFloatingWindowIfNeeded()
        mBinding.reuseLoading.root.visibility = View.GONE

        mAdapter = DescAdapter(requireContext(), mEntrance, mViewModel, mNewDetailEntity)
        (mBinding.recyclerview.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
        mLayoutManager = LinearLayoutManager(context)
        mBinding.recyclerview.layoutManager = mLayoutManager
        mBinding.recyclerview.adapter = mAdapter

        mBinding.recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                val firstCompletelyVisibleItemPosition = mLayoutManager!!.findFirstCompletelyVisibleItemPosition()
                val lastCompletelyVisibleItemPosition = mLayoutManager!!.findLastCompletelyVisibleItemPosition()

                for (i in firstCompletelyVisibleItemPosition..lastCompletelyVisibleItemPosition) {
                    if (i < 0) continue

                    if (mAdapter?.getItemViewType(i) == DescAdapter.CUSTOM_COLUMN
                        && mAdapter!!.descItemList[i].customColumn?.showExpandTagsHint == true
                    ) {
                        SPUtils.setBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT, true)
                    }
                }
            }

            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    EventBus.getDefault().post(EBTypeChange(GameDetailFragment.EB_SCROLLING, 0))
                }

                exposureScroll(newState)
            }
        })
        exposureScroll(RecyclerView.SCROLL_STATE_IDLE)
    }

    private fun exposureScroll(newState: Int) {
        if (newState == RecyclerView.SCROLL_STATE_IDLE) {
            val layoutManager = mBinding.recyclerview.layoutManager as? LinearLayoutManager
            val firstVisibleItem = layoutManager?.findFirstCompletelyVisibleItemPosition() ?: -1
            val lastVisibleItem = layoutManager?.findLastCompletelyVisibleItemPosition() ?: -1
            val childCount = mBinding.recyclerview.adapter?.itemCount ?: 0
            if (firstVisibleItem == -1 || lastVisibleItem == -1) return
            for (i in 0 until childCount) {
                val viewHolder = mBinding.recyclerview.findViewHolderForAdapterPosition(i)
                if (viewHolder != null && viewHolder is ExposureViewHolder) {
                    if (i in firstVisibleItem..lastVisibleItem) {
                        val rect = Rect()
                        viewHolder.itemView.getLocalVisibleRect(rect)
                        if (rect.top == 0 && rect.bottom == viewHolder.itemView.height) {
                            viewHolder.startDelayLogRunnable()
                        }
                    } else {
                        viewHolder.removeLogRunnable()
                    }
                }
            }
        }
    }

    override fun onFragmentPause() {
        super.onFragmentPause()

        val childCount = mBinding.recyclerview.adapter?.itemCount ?: 0
        for (i in 0 until childCount) {
            val viewHolder = mBinding.recyclerview.findViewHolderForAdapterPosition(i)
            if (viewHolder is ExposureViewHolder) {
                viewHolder.removeLogRunnable()
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        mCompositeDisposable.dispose()
        mAdapter?.stopHandlerThread()
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(reuse: EBReuse) {
        if (SKIP_DESC == reuse.type) {
            mAdapter?.notifyDataSetChanged()
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(bean: EBScroll) {
        if (mGameEntity?.id == bean.id) {
            val position = mViewModel.getGameInfoPosition()
            (mBinding.recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position, 0)
        }
    }

    override fun scrollToTop() {
        if (::mBinding.isInitialized) {
            mBinding.recyclerview.scrollToPosition(0)
        }
    }

    fun scrollToRelatedVersion() {
        if (mViewModel.getRelatedVersionPosition() != -1) {
            mLayoutManager?.scrollToPositionWithOffset(mViewModel.getRelatedVersionPosition(), 0)
        }
    }

    fun scrollToLibao() {
        if (mViewModel.getDetailLibaoPosition() != -1) {
            mLayoutManager?.scrollToPositionWithOffset(mViewModel.getDetailLibaoPosition(), 0)
        }
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        mBinding.recyclerview.setBackgroundColor(R.color.background.toColor(requireContext()))
        mBinding.recyclerview.recycledViewPool.clear()
        mAdapter?.let { it.notifyItemRangeChanged(0, it.itemCount) }
    }

    private fun showFloatingWindowIfNeeded() {
        val floatingWindowProvider =
            ARouter.getInstance().build(RouteConsts.provider.floatingwindow).navigation() as? IFloatingWindowProvider

        floatingWindowProvider?.getFloatingWindow(
            mGameEntity?.id ?: "",
            mGameEntity?.name ?: "",
            this,
            mBinding.recyclerview
        )?.let {
            mCompositeDisposable.add(it)
        }
    }

}