package com.gh.gamecenter.category2

import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import com.ethanhua.skeleton.Skeleton
import com.gh.gamecenter.common.constant.Constants
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.DialogUtils
import com.gh.common.view.CategoryFilterView
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.baselist.ListFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.FragmentCategoryListBinding
import com.gh.gamecenter.databinding.LayoutSelectedCategoryBinding
import com.gh.gamecenter.entity.CategoryEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.entity.SubjectSettingEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.google.android.flexbox.FlexboxLayout
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode

class CategoryV2ListFragment : ListFragment<GameEntity, CategoryV2ListViewModel>() {

    private var mCategoryId: String = ""
    private var mSubCategoryId: String = ""
    private var mCategoryTitle: String = ""
    private var mAdapter: CategoryV2ListAdapter? = null
    private var mSelectedViewList = ArrayList<View>()
    private var mBinding: FragmentCategoryListBinding? = null
    private var mCategoryViewModel: CategoryV2ViewModel? = null
    private var mLastPageDataMap: HashMap<String, String>? = null
    private val mDataWatcher = object : DataWatcher() {
        override fun onDataChanged(downloadEntity: DownloadEntity) {
            mAdapter?.notifyItemByDownload(downloadEntity)

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

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

    override fun getLayoutId() = 0

    override fun getInflatedLayout() =
        FragmentCategoryListBinding.inflate(layoutInflater).apply { mBinding = this }.root

    override fun provideListViewModel() =
        viewModelProvider<CategoryV2ListViewModel>(
            CategoryV2ListViewModel.Factory(
                mCategoryId,
                mSubCategoryId,
                arguments?.getParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST)
            )
        )

    override fun provideListAdapter() = mAdapter
        ?: CategoryV2ListAdapter(
            requireContext(),
            mListViewModel ?: provideListViewModel(),
            mCategoryViewModel ?: viewModelProviderFromParent(
                CategoryV2ViewModel.Factory(
                    mCategoryId,
                    mCategoryTitle
                ), mCategoryId
            ),
            mEntrance,
            mLastPageDataMap
        ).apply { mAdapter = this }

    override fun getItemDecoration() = null

    override fun onCreate(savedInstanceState: Bundle?) {
        mCategoryId = arguments?.getString(EntranceConsts.KEY_CATEGORY_ID) ?: ""
        mSubCategoryId = arguments?.getString(EntranceConsts.KEY_SUB_CATEGORY_ID) ?: ""
        mCategoryTitle = arguments?.getString(EntranceConsts.KEY_CATEGORY_TITLE) ?: ""
        mLastPageDataMap = arguments?.getSerializable(EntranceConsts.KEY_LAST_PAGE_DATA) as? HashMap<String, String>
        mCategoryViewModel =
            viewModelProviderFromParent(CategoryV2ViewModel.Factory(mCategoryId, mCategoryTitle), mCategoryId)
        mEntrance = arguments?.getString(EntranceConsts.KEY_ENTRANCE) ?: Constants.ENTRANCE_UNKNOWN

        super.onCreate(savedInstanceState)
        mBinding?.reuseNoneData?.reuseResetLoadTv?.visibility = View.VISIBLE
        mBinding?.reuseNoneData?.reuseNoneDataTv?.text = getString(R.string.game_empty_second)
        mBinding?.reuseNoneData?.reuseNoneDataDescTv?.visibility = View.VISIBLE
        mBinding?.reuseNoneData?.reuseNoneDataDescTv?.text = getString(R.string.game_empty_second_desc)
        mBinding?.reuseNoneData?.reuseResetLoadTv?.text = "重置"
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        initFilterView()

        mListViewModel?.refresh?.observeNonNull(viewLifecycleOwner) { onRefresh() }
        mCategoryViewModel?.run {
            categoryPositionLiveData.observeNonNull(viewLifecycleOwner) {
                directories[it.first].data?.get(it.second)?.run {
                    mBinding?.selectedCategoryContainer?.visibility = View.VISIBLE

                    if (selected) {
                        addCategory(this)
                    } else {
                        removeCategory(this)
                    }
                }
            }
        }

        mListRv.addOnScrollListener(ExposureListener(this, provideListAdapter()))

        mSkeletonScreen = Skeleton.bind(mBinding?.listSkeleton)
            .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_category_game_list_skeleton)
            .show()

        mBinding?.reuseNoneData?.reuseResetLoadTv?.setOnClickListener {
            mCategoryViewModel?.run {
                logClickReset("游戏列表")
                resetDirectoryList()
            }
            resetSortSize()
            changeCategoryTab()
//            openDirectoryLayout()
        }
    }

    private fun resetSortSize() {
        mBinding?.filterContainer?.resetSortSize()
        mListViewModel?.sortSize = SubjectSettingEntity.Size(min = -1, max = -1, text = "全部大小")

    }

    private fun initFilterView() {
        mBinding?.filterContainer?.run {
            visibility = View.VISIBLE

            setOnConfigSetupListener(object : CategoryFilterView.OnCategoryFilterSetupListener {
                override fun onSetupSortSize(sortSize: SubjectSettingEntity.Size) {
                    mListViewModel?.updateSortConfig(sortSize = sortSize)
                }

                override fun onSetupSortType(sortType: CategoryFilterView.SortType) {
                    mListViewModel?.updateSortConfig(sortType = sortType)
                }

                override fun onSetupSortCategory() {
                    openDirectoryLayout()
                }
            })

            setOnFilterClickListener(object : CategoryFilterView.OnFilterClickListener {
                override fun onCategoryClick() {
                    removeGuide()
                }

                override fun onTypeClick() {
                    removeGuide()
                }

                override fun onSizeClick() {
                    removeGuide()
                }

            })
        }
    }

    fun updateSubCategoryId(id: String) {
        mSubCategoryId = id
    }

    fun changeCategoryTab(categoryId: String? = null) {
        mSelectedViewList.clear()
        mBinding?.selectedCategoryContainer?.run {
            removeAllViews()
            visibility = View.GONE
        }
        if (categoryId != null) mSubCategoryId = categoryId
        mListViewModel?.updateSortConfig(categoryIds = mSubCategoryId)
    }

    private fun addCategory(entity: CategoryEntity) {
        addCategoryView(entity)
        mCategoryViewModel?.selectedCategoryList?.add(entity)
        updateCategoryGame()
    }

    private fun removeCategory(entity: CategoryEntity) {
        mCategoryViewModel?.selectedCategoryList?.run {
            if (isEmpty()) return

            removeCategoryView(entity.name ?: "")
            remove(entity)
            if (size == 0) {
                mBinding?.selectedCategoryContainer?.visibility = View.GONE
                mListViewModel?.updateSortConfig(categoryIds = mSubCategoryId)
            } else {
                updateCategoryGame()
            }
        }
    }

    private fun addCategoryView(entity: CategoryEntity) {
        val binding = LayoutSelectedCategoryBinding.inflate(layoutInflater).apply {
            val params =
                FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
            params.setMargins(0, 8F.dip2px(), 8F.dip2px(), 0)
            params.height = 24F.dip2px()
            root.layoutParams = params

            name.text = entity.name
            root.setOnClickListener {
                removeCategoryAndNotify(entity)
            }
        }

        mSelectedViewList.add(binding.root)
        mBinding?.selectedCategoryContainer?.addView(binding.root)
    }

    private fun removeCategoryView(categoryName: String) {
        mCategoryViewModel?.selectedCategoryList?.run {
            var i = 0
            forEachIndexed { index, categoryEntity ->
                if (categoryName == categoryEntity.name) {
                    i = index
                }
            }

            if (i < mSelectedViewList.size) {
                mBinding?.selectedCategoryContainer?.removeView(mSelectedViewList[i])
                mSelectedViewList.removeAt(i)
            }
        }
    }

    private fun removeCategoryAndNotify(entity: CategoryEntity) {
        removeCategory(entity)
        entity.selected = false
        mCategoryViewModel?.run {
            if (selectedCount > 0) {
                selectedCount--
                postSelectedCount()
                postCategoryDirectoryList()
                logClickClassificationDelete(entity.primaryIndex, entity.name ?: "", "游戏列表")
            }
        }
    }

    private fun updateCategoryGame() {
        mCategoryViewModel?.selectedCategoryList?.run {
            val categoryIds = StringBuilder()
            forEachIndexed { index, s ->
                categoryIds.append(s.id)
                if (index != size - 1) {
                    categoryIds.append("-")
                }
            }
            mListViewModel?.updateSortConfig(categoryIds = categoryIds.toString())
        }
    }

    private fun removeGuide() {
        (parentFragment as? CategoryV2Fragment)?.removeGuide()
    }

    override fun onResume() {
        super.onResume()
        DownloadManager.getInstance().addObserver(mDataWatcher)
    }

    override fun onPause() {
        super.onPause()
        DownloadManager.getInstance().removeObserver(mDataWatcher)
    }

    override fun onRefresh() {
        mAdapter?.clearPositionAndPackageMap()

        super.onRefresh()
    }

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

    // 安装/卸载 事件
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEventMainThread(busFour: EBPackage) {
        if (busFour.isInstalledOrUninstalled()) {
            mAdapter?.notifyDataSetChanged()
        }
    }

    fun showUnzipFailureDialog(downloadEntity: DownloadEntity) {
        val data = mAdapter?.positionAndPackageMap ?: return
        for (gameAndPosition in data) {
            if (gameAndPosition.key.contains(downloadEntity.packageName)) {
                val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value)
                if (targetView != null) {
                    DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
                    return
                }
            }
        }
    }

    fun openDirectoryLayout() {
        (parentFragment as? CategoryV2Fragment)?.openDirectoryLayout()
    }

    override fun onDarkModeChanged() {
        super.onDarkModeChanged()
        mBinding?.filterContainer?.run {
            setRootBackgroundColor(R.color.background_white.toColor(requireContext()))
            setItemTextColor(R.color.text_subtitle.toColor(requireContext()))
            updatePopupWindow()
        }
    }
}