package com.gh.gamecenter.common.base.adapter

import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DiffUtil
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.gh.gamecenter.common.utils.safelyGetInRelease

/**
 * 支持diff刷新的FragmentStateAdapter
 */
abstract class BaseDiffFragmentStateAdapter<T>(fragment: Fragment) : FragmentStateAdapter(fragment) {
    protected var mDataList = ArrayList<T>()

    fun getFragmentTag(position: Int) = "f${getItemId(position)}"

    fun submitList(dataList: List<T>) {
        if (mDataList.isEmpty()) {
            mDataList.addAll(dataList)
            notifyDataSetChanged()
        } else {
            val originData = ArrayList(mDataList)
            val updateDataCopy = ArrayList(dataList)

            if (originData.containsAll(updateDataCopy) && originData.size == updateDataCopy.size) return

            val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
                override fun getOldListSize(): Int {
                    return originData.size
                }

                override fun getNewListSize(): Int {
                    return updateDataCopy.size
                }

                override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                    val oldItem = originData.safelyGetInRelease(oldItemPosition)
                    val newItem = updateDataCopy.safelyGetInRelease(newItemPosition)
                    return areItemsTheSame(oldItem, newItem)
                }

                override fun areContentsTheSame(
                    oldItemPosition: Int,
                    newItemPosition: Int
                ): Boolean {
                    val oldItem = originData.safelyGetInRelease(oldItemPosition)
                    val newItem = updateDataCopy.safelyGetInRelease(newItemPosition)
                    return areContentsTheSame(oldItem, newItem)
                }
            })

            mDataList = updateDataCopy
            diffResult.dispatchUpdatesTo(this)
        }
    }

    protected open fun areItemsTheSame(oldItem: T?, newItem: T?): Boolean = oldItem == newItem
    protected open fun areContentsTheSame(oldItem: T?, newItem: T?): Boolean = oldItem == newItem

    override fun getItemCount(): Int = mDataList.size

    override fun createFragment(position: Int): Fragment = createFragment(mDataList.safelyGetInRelease(position), position) ?: Fragment()

    abstract fun createFragment(data: T?, position: Int): Fragment?

    override fun getItemId(position: Int): Long {
        if (mDataList.size <= position) {
            return 0L
        }
        return mDataList[position].hashCode().toLong()
    }

    override fun containsItem(itemId: Long): Boolean {
        mDataList.forEach {
            if (it.hashCode().toLong() == itemId) {
                return true
            }
        }
        return false
    }
}