package com.adealink.weparty.ui.category

import android.content.Intent
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.adealink.frame.base.fastLazy
import com.adealink.frame.ext.isViewBindingValid
import com.adealink.frame.mvvm.view.viewBinding
import com.adealink.frame.router.Router
import com.adealink.frame.util.DisplayUtil
import com.adealink.weparty.R
import com.adealink.weparty.commonui.BaseFragment
import com.adealink.weparty.commonui.ext.dp
import com.adealink.weparty.commonui.recycleview.adapter.MultiTypeListAdapter
import com.adealink.weparty.commonui.recycleview.diffutil.BaseListDiffUtil
import com.adealink.weparty.commonui.recycleview.itemdecoration.GridSpacingMultiSpanSizeItemDecoration
import com.adealink.weparty.commonui.recycleview.itemdecoration.VerticalSpaceItemDecoration
import com.adealink.weparty.databinding.FragmentCategoryBinding
import com.adealink.weparty.module.category.Category
import com.adealink.weparty.module.category.data.CategoryAction
import com.adealink.weparty.module.joinus.JoinUs
import com.adealink.weparty.module.playmate.Playmate
import com.adealink.weparty.module.playmate.PlaymateModule
import com.adealink.weparty.ui.category.adapter.CategoryListBottomViewBinder
import com.adealink.weparty.ui.category.adapter.CategoryListItemViewBinder
import com.adealink.weparty.ui.category.adapter.CategoryListTitleViewBinder
import com.adealink.weparty.ui.category.adapter.CategoryTabTitleViewBinder
import com.adealink.weparty.ui.category.data.CategoryItemData
import com.adealink.weparty.ui.category.data.CategoryListBottomData
import com.adealink.weparty.ui.category.data.CategoryListItemData
import com.adealink.weparty.ui.category.data.CategoryListTitleData
import kotlin.math.max


class CategoryFragment : BaseFragment(R.layout.fragment_category) {

    companion object {
        const val TAG = "CategoryFragment"
        private const val SPAN_COUNT = 3
    }

    private val binding by viewBinding(FragmentCategoryBinding::bind)

    private val titleAdapter by fastLazy { MultiTypeListAdapter<CategoryItemData>(BaseListDiffUtil()) }
    private val listAdapter by fastLazy { MultiTypeListAdapter<CategoryItemData>(BaseListDiffUtil()) }

    private val categoryViewModel by fastLazy { PlaymateModule.getPlaymateViewModel(this) }

    private lateinit var titleLayoutManger: LinearLayoutManager
    private lateinit var listLayoutManger: GridLayoutManager

    private var titleList = listOf<CategoryListTitleData>()
    private var itemList = listOf<CategoryItemData>()


    //Item到Tab的位置映射
    private var itemToTitlePosition = mutableListOf<Int>()
    private var titleToItemPosition = mutableListOf<Int>()

    private var action: CategoryAction = CategoryAction.FIND_PLAYMATE
    private var hiddenCategorys = arrayListOf<String>()

    override fun initViews() {
        super.initViews()
        action = CategoryAction.map(
            arguments?.getInt(
                Category.CategoryList.EXTRA_SELECT_ACTION,
                CategoryAction.FIND_PLAYMATE.action
            )
        )
        hiddenCategorys.clear()
        hiddenCategorys.addAll(
            arguments?.getStringArrayList(
                Category.CategoryList.EXTRA_HIDDEN_CATEGORY
            ) ?: emptyList()
        )
        initTab()
        initList()
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        if (!isViewBindingValid()) {
            return
        }
        action = CategoryAction.map(
            arguments?.getInt(
                Category.CategoryList.EXTRA_SELECT_ACTION,
                CategoryAction.FIND_PLAYMATE.action
            )
        )
        hiddenCategorys.clear()
        hiddenCategorys.addAll(
            arguments?.getStringArrayList(
                Category.CategoryList.EXTRA_HIDDEN_CATEGORY
            ) ?: emptyList()
        )
        loadData()
    }

    private fun initTab() {
        binding.rvTab.adapter = titleAdapter
        titleAdapter.register(CategoryTabTitleViewBinder { _, position ->
            selectTitle(position)
        })
        titleLayoutManger = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
        binding.rvTab.layoutManager = titleLayoutManger
        binding.rvTab.addItemDecoration(
            VerticalSpaceItemDecoration(24.dp())
        )
    }

    private fun initList() {
        binding.rvList.adapter = listAdapter
        listAdapter.register(CategoryListTitleViewBinder())
        listAdapter.register(CategoryListItemViewBinder { item, position ->
            selectItem(item)
        })
        listAdapter.register(CategoryListBottomViewBinder())
        listLayoutManger = GridLayoutManager(context, SPAN_COUNT, RecyclerView.VERTICAL, false)
        listLayoutManger.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
            override fun getSpanSize(position: Int): Int {
                val data = listAdapter.items.getOrNull(position)
                if (data is CategoryListTitleData
                    || data is CategoryListBottomData
                ) {
                    return SPAN_COUNT
                }
                return 1
            }
        }
        binding.rvList.layoutManager = listLayoutManger
        binding.rvList.addItemDecoration(
            GridSpacingMultiSpanSizeItemDecoration(SPAN_COUNT, 12.dp(), 10.dp(), false)
        )
        binding.rvList.addOnScrollListener(itemScrollListener)
    }

    private val itemScrollListener = object : RecyclerView.OnScrollListener() {

        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            if (skipScrollTitle) {
                skipScrollTitle = false
                return
            }
            val firstVisibleItemPosition = listLayoutManger.findFirstVisibleItemPosition()
            if (firstVisibleItemPosition != RecyclerView.NO_POSITION) {
                scrollToTitle(firstVisibleItemPosition)
            }
        }
    }

    private var skipScrollTitle = false
    private fun selectTitle(selectPosition: Int) {
        val toPosition = titleToItemPosition.getOrNull(selectPosition)
        if (toPosition != null && toPosition >= 0) {
            updateTitleTab(selectPosition)
            skipScrollTitle = true
            listLayoutManger.scrollToPositionWithOffset(
                toPosition,
                if (toPosition == 0) {
                    0
                } else {
                    (-48).dp()
                }
            )
        }
    }

    private fun updateTitleTab(selectPosition: Int) {
        titleList.forEachIndexed { index, data ->
            val nextSelected = index == selectPosition
            if (nextSelected != data.selected) {
                data.selected = nextSelected
                titleAdapter.notifyItemChanged(index)
            }
        }
    }

    private fun scrollToTitle(position: Int) {
        val titlePosition = itemToTitlePosition.getOrNull(position)
        if (titlePosition != null && titlePosition >= 0) {
            updateTitleTab(titlePosition)
            titleLayoutManger.scrollToPositionWithOffset(position, 0)
        }
    }


    override fun loadData() {
        super.loadData()
        categoryViewModel?.pullAllCategory()
    }

    override fun observeViewModel() {
        super.observeViewModel()
        categoryViewModel?.allCategoryLD?.observe(viewLifecycleOwner) { categoryList ->
            val titleList = mutableListOf<CategoryListTitleData>()
            val itemList = mutableListOf<CategoryItemData>()

            var titlePosition = -1
            for (data in categoryList) {
                //判断该大品类是否都需要隐藏
                val subCategoryCodes = data.subCategoryList.map { it.code }
                if (isHidden(subCategoryCodes)) {
                    continue
                }
                titlePosition++
                titleList.add(CategoryListTitleData(data))
                itemList.add(
                    CategoryListTitleData(
                        data,
                        marginTop = if (titlePosition == 0) {
                            0
                        } else {
                            48.dp()
                        }
                    )
                )
                itemToTitlePosition.add(titlePosition)
                titleToItemPosition.add(itemList.size - 1)

                for (subData in data.subCategoryList) {
                    if (isHidden(listOf(subData.code))) {
                        continue
                    }
                    itemToTitlePosition.add(titlePosition)
                    itemList.add(CategoryListItemData(data.code, subData))
                }
            }
            itemList.add(CategoryListBottomData(DisplayUtil.getScreenHeight()))
            submitCategoryList(titleList, itemList)
        }
    }

    private fun isHidden(categoryList: List<String>): Boolean {
        for (categoryCode in categoryList) {
            if (!hiddenCategorys.contains(categoryCode)) {
                return false
            }
        }
        return true
    }

    private fun submitCategoryList(
        titleList: List<CategoryListTitleData>,
        itemList: List<CategoryItemData>
    ) {
        this.titleList = titleList
        titleAdapter.submitList(titleList)
        this.itemList = itemList
        listAdapter.submitList(itemList, committed = {
            calcBottomSpace(titleList, itemList)
        })
    }

    private fun calcBottomSpace(
        titleList: List<CategoryListTitleData>,
        itemList: List<CategoryItemData>
    ) {
        binding.rvList.post {
            if (isViewBindingValid()) {
                val lastTab = titleList.lastOrNull() ?: return@post
                var lastTabHeight = 0
                if (titleList.size > 1) {
                    lastTabHeight += (36 + 48).dp()
                } else {
                    lastTabHeight += 36.dp()
                }

                val line = if (lastTab.data.subCategoryList.size % SPAN_COUNT == 0) {
                    lastTab.data.subCategoryList.size / SPAN_COUNT
                } else {
                    (lastTab.data.subCategoryList.size + SPAN_COUNT) / SPAN_COUNT
                }
                lastTabHeight += line * 66.dp() + max(line - 1, 0) * 10.dp()

                val bottomItem = itemList.lastOrNull()
                if (bottomItem is CategoryListBottomData) {
                    bottomItem.height = max(binding.rvList.height - lastTabHeight, 0)
                    listAdapter.notifyItemChanged(itemList.size - 1)
                }
            }
        }
    }

    private fun selectItem(item: CategoryListItemData) {
        val act = activity ?: return
        when (action) {
            CategoryAction.FIND_PLAYMATE -> {
                Router.build(act, Playmate.List.PATH)
                    .putExtra(Playmate.Common.EXTRA_FIRST_CATEGORY_CODE, item.firstCode)
                    .putExtra(Playmate.Common.EXTRA_CATEGORY, item.data)
                    .start()
            }

            CategoryAction.APPLY_SKILL -> {
                Router.build(act, JoinUs.ApplySKill.PATH)
                    .putExtra(JoinUs.ApplySKill.EXTRA_CATEGORY, item.data)
                    .start()
            }
        }
    }


}