package com.ama.core.architecture.base.views.adapter

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.AdapterListUpdateCallback
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.ama.core.architecture.util.setFragmentIsLazyInit
import com.ama.core.model.BaseFragmentStateDiffItem


@Suppress("LeakingThis", "MemberVisibilityCanBePrivate")
abstract class BaseFragmentStateAdapter<T : BaseFragmentStateDiffItem>(
    private val fragmentManager: FragmentManager,
    lifecycle: Lifecycle,
    private val isFragmentLazyInit: Boolean,
) : FragmentStateAdapter(fragmentManager, lifecycle) {
    private var mDiffer: AsyncListDiffer<T> = AsyncListDiffer(
        AdapterListUpdateCallback(this),
        AsyncDifferConfig.Builder(BaseDiffItemCallback<T>()).build()
    )

    constructor(
        activity: FragmentActivity,
        isFragmentLazyInit: Boolean,
    ) : this(activity.supportFragmentManager, activity.lifecycle, isFragmentLazyInit)

    constructor(
        fragment: Fragment, isFragmentLazyInit: Boolean,
    ) : this(fragment.childFragmentManager, fragment.lifecycle, isFragmentLazyInit)

    override fun getItemCount(): Int {
        return mDiffer.currentList.size
    }

    override fun createFragment(position: Int): Fragment {
        return createFragment(position, getItem(position))
            .setFragmentIsLazyInit(isFragmentLazyInit)
    }

    override fun getItemId(position: Int): Long {
        return getItem(position).getItemId()
    }

    override fun containsItem(itemId: Long): Boolean {
        return getCurrentList().any { it.getItemId() == itemId }
    }

    abstract fun createFragment(position: Int, item: T): Fragment

    fun submitList(list: List<T>?) {
        mDiffer.submitList(list)
    }

    fun appendList(appendList: List<T>?) {
        val newList = mutableListOf<T>()
        newList.addAll(getCurrentList())
        newList?.let {
            newList.addAll(appendList!!)
        }
        mDiffer.submitList(newList)
    }

    fun getFragmentByIndex(position: Int) =
        if (position in 0..<itemCount) fragmentManager.findFragmentByTag("f" + getItemId(position)) else null

    fun getCurrentList(): List<T> {
        return mDiffer.currentList
    }

    fun getItem(position: Int): T {
        return mDiffer.currentList[position]
    }
}