package com.gh.gamecenter.servers

import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.widget.CheckedTextView
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.RelativeLayout
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager
import com.ethanhua.skeleton.Skeleton
import com.ethanhua.skeleton.ViewSkeletonScreen
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.common.exposure.ExposureListener
import com.gh.gamecenter.feature.exposure.ExposureSource
import com.gh.common.util.*
import com.gh.gamecenter.common.view.DrawableView
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.constant.EntranceConsts
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.safelyGetInRelease
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.PageSwitchDataHelper
import com.gh.gamecenter.databinding.FragmentGameServersBinding
import com.gh.gamecenter.databinding.FragmentKaifuContentBinding
import com.gh.gamecenter.databinding.PopupServerStatusBinding
import com.gh.gamecenter.databinding.PopupTestTimeBinding
import com.gh.gamecenter.eventbus.EBDownloadStatus
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 GameServersTestFragment : LazyFragment() {

    private var mBinding: FragmentGameServersBinding? = null
    private var mSubBinding: FragmentKaifuContentBinding? = null
    private var mViewModel: GameServersTestViewModel? = null
    private var mAdapter: GameServersTestAdapter? = null
    private var mSkeleton: ViewSkeletonScreen? = null

    private var mExposureListener: ExposureListener? = null

    private var mDay: String? = null
    private var mType: String = GameServersTestViewModel.ALL

    private var mSupremeSelectedDay: String? = null // 手动选择的日期，优先级高，当它存在时忽略滚动的选中
    private var mShouldScrollToToday = true

    private var mTestColumnId = DEFAULT_TEST_COLUMN_ID

    private var mIsRefreshDownload = true

    private val dataWatcher: DataWatcher = object : DataWatcher() {
        override fun onDataChanged(downloadEntity: DownloadEntity) {
            val locationList = mViewModel?.locationMap?.get(downloadEntity.packageName)
            if (locationList != null && mIsRefreshDownload) {
                for (location in locationList) {
                    // FIXME 多线程读可能会出现数组越界或没有更新成功的情况
                    mViewModel?.listLiveData?.value?.safelyGetInRelease(location)?.game?.let { gameEntity ->
                        DownloadItemUtils.processDate(gameEntity, downloadEntity, mAdapter, location)
                    }
                }
                if (XapkUnzipStatus.FAILURE.name == downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS]) {
                    for (position in locationList) {
                        val targetView = mSubBinding?.recyclerView?.layoutManager?.findViewByPosition(position)
                        if (targetView != null) {
                            DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
                            break
                        }
                    }
                }
            }
        }
    }

    override fun getRealLayoutId() = R.layout.fragment_game_servers

    override fun onRealLayoutInflated(inflatedView: View) {
        mBinding = FragmentGameServersBinding.bind(inflatedView)
    }

    override fun onFragmentFirstVisible() {
        mTestColumnId = arguments?.getString(TEST_COLUMN_ID, DEFAULT_TEST_COLUMN_ID)
            ?: DEFAULT_TEST_COLUMN_ID

        mViewModel = viewModelProviderFromParent(GameServersTestViewModel.Factory(HaloApp.getInstance(), mTestColumnId))

        super.onFragmentFirstVisible()

        val title = arguments?.getString(TEST_TITLE)
        setNavigationTitle(title)

        mViewModel?.testTitle = title ?: "总开测表"
        mViewModel?.listLiveData?.observe(this, Observer {
            if (it.isEmpty()) {
                showNoContentError()
            } else {
                mAdapter?.submitList(it)
                // 切换筛选条件的时候滚动到已选择的日期
                if (mDay != null) {
                    scrollToDay(mDay!!)
                }

                if (mShouldScrollToToday) {
                    mShouldScrollToToday = false
                    scrollToDay("今天")
                }
                mSubBinding?.root?.post {
                    mSubBinding?.recyclerView?.visibility = View.VISIBLE
                    hideError()
                }
            }
        })
        mViewModel?.loadStatusLiveData?.observe(this, Observer { isSuccess ->
            if (!isSuccess) {
                showConnectionError()
            }
        })
    }

    override fun initRealView() {
        super.initRealView()

        mSubBinding = mBinding?.layoutFragmentContent

        mSubBinding?.root?.setBackgroundColor(R.color.background_white.toColor(requireContext()))
        mSkeleton = Skeleton.bind(mSubBinding?.skeleton)
            .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)
            .load(R.layout.fragment_game_servers_skeleton)
            .show()
        mViewModel?.load()

        if (isStandalonePage()) {
            showStandaloneFilter()
        } else {
            showDefaultFilter()
        }

        val exposureSource = if (arguments?.getParcelable<ExposureSource>(EntranceConsts.KEY_EXPOSURE_SOURCE) != null) {
            listOf<ExposureSource>(arguments?.getParcelable(EntranceConsts.KEY_EXPOSURE_SOURCE)!!)
        } else {
            null
        }

        mAdapter = GameServersTestAdapter(
            requireContext(),
            mViewModel!!,
            { mSubBinding?.recyclerView?.scrollToPosition(0) },
            exposureSource,
            mEntrance
        )

        logEntranceIfNeeded()

        mExposureListener = ExposureListener(this, mAdapter!!)

        (mSubBinding?.recyclerView?.itemAnimator as DefaultItemAnimator?)?.supportsChangeAnimations = false
        mSubBinding?.recyclerView?.layoutManager = LinearLayoutManager(requireContext())
        mSubBinding?.recyclerView?.addOnScrollListener(mExposureListener!!)
        mSubBinding?.recyclerView?.adapter = mAdapter
        mSubBinding?.recyclerView?.clipToPadding = false

        mSubBinding?.recyclerView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                val layoutManager = recyclerView.layoutManager
                if (layoutManager is LinearLayoutManager) {
                    val firstVisiblePosition = layoutManager.findFirstVisibleItemPosition()

                    val filterDay = mViewModel?.getDayRangeByPosition(firstVisiblePosition)

                    if (mSupremeSelectedDay == null && !filterDay.isNullOrEmpty()) {
                        mViewModel?.updateTimeFilter(filterDay)
                        mBinding?.filterView?.updateSelectedMainFilter(filterDay)
                        mBinding?.serverTime?.text = filterDay
                        mBinding?.serverTime?.setTextColor(R.color.theme_font.toColor(requireContext()))
                    }

                    // 悬挂的文案
                    mSubBinding?.kaifuTimeContainer?.kaifuItemTime?.goneIf(firstVisiblePosition == 0)
                    mSubBinding?.kaifuTimeContainer?.kaifuItemTimeTv?.text =
                        mViewModel?.getDayTextByPosition(firstVisiblePosition)

                    // 悬挂界面移动
                    val lp = mSubBinding?.kaifuTimeContainer?.kaifuItemTime?.layoutParams as RelativeLayout.LayoutParams
                    if (firstVisiblePosition != 0
                        && mViewModel?.getItemAtPosition(firstVisiblePosition + 1)?.time != null
                    ) {
                        val bottom = layoutManager.findViewByPosition(firstVisiblePosition)?.bottom ?: 0
                        if (bottom <= mSubBinding?.kaifuTimeContainer?.kaifuItemTime?.height ?: 0) {
                            lp.topMargin = bottom - (mSubBinding?.kaifuTimeContainer?.kaifuItemTime?.height ?: 0)
                        } else {
                            lp.topMargin = 0
                        }
                    } else {
                        lp.topMargin = 0
                    }
                    mSubBinding?.kaifuTimeContainer?.kaifuItemTime?.layoutParams = lp
                }
            }

            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                if (newState == RecyclerView.SCROLL_STATE_IDLE && !mSupremeSelectedDay.isNullOrEmpty()) {
                    mViewModel?.updateTimeFilter(mSupremeSelectedDay!!)
                    mBinding?.filterView?.updateSelectedMainFilter(mSupremeSelectedDay!!)
                    mBinding?.serverTime?.text = mSupremeSelectedDay
                    mBinding?.serverTime?.setTextColor(R.color.theme_font.toColor(requireContext()))
                    mSupremeSelectedDay = null
                }
                if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    mSupremeSelectedDay = null
                }
            }
        })
    }

    override fun onFragmentResume() {
        super.onFragmentResume()
        if (mAdapter != null) {
            mAdapter?.notifyDataSetChanged()
            DownloadManager.getInstance().addObserver(dataWatcher)
        }
    }

    override fun onFragmentPause() {
        super.onFragmentPause()
        DownloadManager.getInstance().removeObserver(dataWatcher)
    }

    private fun showStandaloneFilter() {
        mBinding?.serverTime?.visibility = View.INVISIBLE
        mBinding?.serverStatus?.visibility = View.INVISIBLE
        mBinding?.backgroundBlock?.visibility = View.GONE

        mBinding?.filterView?.visibility = View.VISIBLE
        mBinding?.filterView?.setupFilter(
            mViewModel!!.dayList,
            mViewModel!!.dayList[2],
            mViewModel!!.typeList,
            "测试状态",
            { day ->
                mDay = day
                mSupremeSelectedDay = day
                scrollToDay(mDay ?: mViewModel!!.dayList.first())
                logTimeFilterSelectedEvent(mDay ?: mViewModel!!.dayList.first())
            },
            { name ->
                mBinding?.serverStatus?.text = if (name == GameServersTestViewModel.ALL) "测试状态" else name
                mType = name

                logTypeFilterSelectedEvent(name)
                mViewModel?.updateTypeFilter(name)
            },
            true
        )

        mBinding?.filterView?.updateSelectedSubFilter(mViewModel!!.typeList.first())
    }

    private fun showDefaultFilter() {
        mBinding?.serverTime?.text = "开测时间"
        mBinding?.serverStatus?.text = "测试状态"
        mBinding?.serverTime?.setOnClickListener {
            showTestTimePopupWindow(it as CheckedTextView, mViewModel!!.dayList) { day ->
                mDay = day

                scrollToDay(mDay ?: mViewModel!!.dayList.first())
                mViewModel?.updateTimeFilter(mDay ?: "")
            }
        }
        mBinding?.serverStatus?.setOnClickListener {
            showServersStatusPopupWindow(it as CheckedTextView, mViewModel!!.typeList) { name ->
                mBinding?.serverStatus?.text = if (name == GameServersTestViewModel.ALL) "测试状态" else name
                mType = name

                mViewModel?.updateTypeFilter(name)
            }
        }
    }

    /**
     * 滚动到具体日期
     */
    private fun scrollToDay(day: String) {
        val positionToScroll = mViewModel!!.getDayPositionByDayString(day)
        if (positionToScroll >= 0) {
            (mSubBinding?.recyclerView?.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
                positionToScroll,
                0
            )
        }
    }

    private fun showServersStatusPopupWindow(
        v: CheckedTextView,
        typeList: ArrayList<String>,
        callback: (String) -> Unit
    ) {
        MtaHelper.onEvent("开服表", "开测Tab", "测试状态")

        v.isChecked = true
        v.setTextColor(R.color.theme_font.toColor(requireContext()))

        val binding = PopupServerStatusBinding.inflate(LayoutInflater.from(context))
        val layout = binding.root
        val popupWindow = PopupWindow(
            layout,
            LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.WRAP_CONTENT
        )

        val tvList = arrayListOf(binding.all, binding.publishServer, binding.notDeleteServer, binding.deleteServer)

        for ((index, tv) in tvList.withIndex()) {
            tv.text = typeList[index]
            if (tv.text.toString() == mType) {
                tv.setTextColor(R.color.theme_font.toColor(requireContext()))
            }
            tv.setOnClickListener {
                callback.invoke(tv.text.toString())
                popupWindow.dismiss()
                MtaHelper.onEvent("开服表", "开测Tab", tv.text.toString())
            }
        }

        layout.setOnClickListener {
            popupWindow.dismiss()
        }

        popupWindow.isTouchable = true
        popupWindow.isFocusable = true

        popupWindow.setOnDismissListener {
            v.isChecked = false
            if (mType == "全部") v.setTextColor(R.color.text_title.toColor(requireContext()))
        }
        popupWindow.showAsDropDown(v)
    }

    private fun showTestTimePopupWindow(v: CheckedTextView, dayList: ArrayList<String>, callback: (String?) -> Unit) {
        MtaHelper.onEvent("开服表", "开测Tab", "开测时间")

        v.isChecked = true
        v.setTextColor(R.color.theme_font.toColor(requireContext()))

        val binding = PopupTestTimeBinding.inflate(LayoutInflater.from(v.context))
        val layout = binding.root
        val popupWindow =
            PopupWindow(layout, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)

        binding.line.visibility = View.GONE

        val tvList =
            arrayListOf(binding.previousTv, binding.yesterdayTv, binding.todayTv, binding.tomorrowTv, binding.afterTv)

        for ((index, tv) in tvList.withIndex()) {
            tv.text = dayList[index]
            tv.setTextColor(
                DrawableView.getSelectorColorStyle(
                    R.color.text_title,
                    R.color.theme_font,
                    requireContext()
                )
            )
            tv.isChecked = tv.text == v.text
            tv.setOnClickListener {
                callback.invoke(tv.text.toString())
                v.text = tv.text
                MtaHelper.onEvent("开服表", "开测Tab", tv.text.toString())
                popupWindow.dismiss()
            }
        }

        layout.setOnClickListener {
            popupWindow.dismiss()
        }

        popupWindow.isTouchable = true
        popupWindow.isFocusable = true

        popupWindow.setOnDismissListener {
            v.isChecked = false
            if (mDay.isNullOrEmpty()) v.setTextColor(R.color.text_title.toColor(requireContext()))
        }
        popupWindow.showAsDropDown(v)
    }

    private fun resetFilter() {
        mType = "全部"
//        mBinding?.serverTime?.text = "开测时间"
        mBinding?.serverStatus?.text = "测试状态"
        mBinding?.filterView?.updateSelectedSubFilter(mViewModel!!.typeList.first())
        mBinding?.serverTime?.setTextColor(R.color.text_title.toColor(requireContext()))
        mBinding?.serverStatus?.setTextColor(R.color.text_title.toColor(requireContext()))
        mSubBinding?.run {
            reuseNoneData.reuseNoneData?.visibility = View.GONE
            noConnectionContainer.root.visibility = View.GONE
            loadingContainer.root.visibility = View.VISIBLE
        }
        mViewModel?.load(GameServersTestViewModel.ALL)
    }

    private fun isStandalonePage() = mTestColumnId != DEFAULT_TEST_COLUMN_ID

    fun vpScrollState(status: Int) {
        if (status == ViewPager.SCROLL_STATE_IDLE) {
            mIsRefreshDownload = true
        } else if (status == ViewPager.SCROLL_STATE_DRAGGING) {
            mIsRefreshDownload = false
        }
    }

    private fun showConnectionError() {
        mSubBinding?.root?.setBackgroundColor(Color.TRANSPARENT)
        mSkeleton?.hide()
        mSubBinding?.recyclerView?.visibility = View.GONE
        mSubBinding?.reuseNoneData?.reuseNoneData?.visibility = View.GONE
        mSubBinding?.noConnectionContainer?.root?.visibility = View.VISIBLE
        mSubBinding?.noConnectionContainer?.root?.setOnClickListener {
            mSubBinding?.root?.setBackgroundColor(R.color.background_white.toColor(requireContext()))
            mSkeleton?.show()
            resetFilter()
        }
        mSubBinding?.loadingContainer?.root?.visibility = View.GONE
    }

    private fun showNoContentError() {
        mSubBinding?.root?.setBackgroundColor(Color.TRANSPARENT)
        mSkeleton?.hide()
        mSubBinding?.recyclerView?.visibility = View.GONE
        mSubBinding?.reuseNoneData?.reuseResetLoadTv?.text = "查看全部"
        mSubBinding?.reuseNoneData?.reuseResetLoadTv?.visibility = View.VISIBLE
        mSubBinding?.reuseNoneData?.reuseNoneData?.visibility = View.VISIBLE
        mSubBinding?.reuseNoneData?.reuseNoneData?.setOnClickListener {
            mSubBinding?.root?.setBackgroundColor(R.color.background_white.toColor(requireContext()))
            mSkeleton?.show()
            resetFilter()
        }
        mSubBinding?.loadingContainer?.root?.visibility = View.GONE
        mSubBinding?.noConnectionContainer?.root?.visibility = View.GONE
    }

    private fun hideError() {
        mSubBinding?.root?.setBackgroundColor(Color.TRANSPARENT)
        mSkeleton?.hide()
        mSubBinding?.noConnectionContainer?.root?.visibility = View.GONE
        mSubBinding?.reuseNoneData?.reuseNoneData?.visibility = View.GONE
        mSubBinding?.loadingContainer?.root?.visibility = View.GONE
    }

    private fun logEntranceIfNeeded() {
        val lastPageData = PageSwitchDataHelper.popLastPageData()
        if (lastPageData != null) {
            LogUtils.logServerTestAccessEvent(
                lastPageData[PageSwitchDataHelper.PAGE_BUSINESS_TYPE],
                lastPageData[PageSwitchDataHelper.PAGE_BUSINESS_NAME],
                mViewModel!!.testTitle,
                mViewModel!!.testRemark
            )
        }
    }

    //下载被删除事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(status: EBDownloadStatus) {
        DownloadManager.getInstance().removePlatform(status.name, status.platform)
        if (status.status == "delete") {
            mViewModel?.locationMap?.get(status.packageName)?.let {
                for (location in it) {
                    mViewModel?.listLiveData?.value?.safelyGetInRelease(location)?.game?.getEntryMap()
                        ?.remove(status.platform)
                    mAdapter?.notifyItemChanged(location)
                }
            }
        }
    }

    private fun logTimeFilterSelectedEvent(time: String) {
        LogUtils.logServerTestSelectTimeEvent(time, mViewModel!!.testTitle, mViewModel!!.testRemark)
    }

    private fun logTypeFilterSelectedEvent(type: String) {
        LogUtils.logServerTestSelectTypeEvent(type, mViewModel!!.testTitle, mViewModel!!.testRemark)
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        mBinding?.run {
            root.setBackgroundColor(R.color.background.toColor(requireContext()))
            filterView.run {
                setRootBackgroundColor(R.color.background_white.toColor(requireContext()))
                updateFilterRecyclerView()
                updatePopupWindow()
            }
        }

        mSubBinding?.run {
            kaifuTimeContainer.run {
                root.setBackgroundColor(R.color.background_white.toColor(requireContext()))
                kaifuItemTimeTv.setTextColor(R.color.text_title.toColor(requireContext()))
            }
            recyclerView.adapter?.run {
                recyclerView.recycledViewPool.clear()
                notifyItemRangeChanged(0, itemCount)
            }
            reuseNoneData.reuseNoneDataTv.setTextColor(R.color.text_title.toColor(requireContext()))
            reuseNoneData.reuseNoneDataDescTv.setTextColor(R.color.text_subtitleDesc.toColor(requireContext()))
            reuseNoneData.reuseNoneDataIv.setImageResource(R.drawable.ic_empty_data)
        }
    }

    companion object {
        const val TEST_COLUMN_ID = "test_column_id"
        const val TEST_TITLE = "title"
        const val DEFAULT_TEST_COLUMN_ID = "general"
    }

}