package com.adealink.frame.imkit.widget.adapter

import android.view.View
import android.view.View.OnLongClickListener
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.collection.SparseArrayCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView

open class BaseAdapter<T> : RecyclerView.Adapter<ViewHolder> {
    private val TAG: String = BaseAdapter::class.java.simpleName
    protected var listener: IViewProviderListener<T>? = null
    protected var dataList: MutableList<T> = ArrayList()
    protected var onItemClickListener: OnItemClickListener? = null
    protected var providerManager: ProviderManager<T> = ProviderManager()
    private val EMPTY_ITEM_VIEW_TYPE = -200
    private var emptyView: View? = null

    @LayoutRes
    private var emptyId = 0
    private val headerViews = SparseArrayCompat<View?>()
    private val footViews = SparseArrayCompat<View?>()

    constructor()

    constructor(listener: IViewProviderListener<T>?, providerManager: ProviderManager<T>) {
        this.listener = listener
        this.providerManager = providerManager
    }

    override fun getItemViewType(position: Int): Int {
        return if (isHeaderViewPos(position)) {
            headerViews.keyAt(position)
        } else if (isFooterViewPos(position)) {
            footViews.keyAt(
                position - (headersCount + (if (isEmpty) 1 else realItemCount))
            )
        } else if (isEmpty) {
            EMPTY_ITEM_VIEW_TYPE
        } else {
            val listPosition = position - headersCount
            // 没有空布局返回真实数值
            providerManager.getItemViewType(dataList[listPosition], listPosition)
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        if (headerViews[viewType] != null) {
            return ViewHolder.createViewHolder(parent.context, headerViews[viewType]!!)
        } else if (footViews[viewType] != null) {
            return ViewHolder.createViewHolder(parent.context, footViews[viewType]!!)
        } else if (viewType == EMPTY_ITEM_VIEW_TYPE) {
            val holder = if (emptyView != null) {
                ViewHolder.createViewHolder(parent.context, emptyView!!)
            } else {
                ViewHolder.createViewHolder(parent.context, parent, emptyId)
            }
            return holder
        } else {
            val provider = providerManager.getProvider(viewType)
            return provider.onCreateViewHolder(parent, viewType)
        }
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        if (isHeaderViewPos(position)) {
            return
        } else if (isFooterViewPos(position)) {
            return
        } else if (isEmpty) {
            return
        } else {
            val listPosition = position - headersCount
            val provider = providerManager.getProvider(dataList[listPosition])
            provider.bindViewHolder(
                holder, dataList[listPosition], listPosition, dataList, listener
            )
            holder.itemView.setOnClickListener { v ->
                onItemClickListener?.onItemClick(v, holder, listPosition)
            }
            holder.itemView.setOnLongClickListener(
                OnLongClickListener { v ->
                    return@OnLongClickListener onItemClickListener?.onItemLongClick(
                        v, holder, listPosition
                    ) ?: false
                })
        }
    }

    override fun getItemCount(): Int {
        return if (isEmpty) {
            headersCount + footersCount + 1
        } else {
            // 没有空布局返回真实数值
            headersCount + footersCount + realItemCount
        }
    }

    open fun setDataCollection(data: List<T>?) {
        if (data != null) {
            dataList.clear()
            dataList.addAll(data)
        }
    }

    fun add(t: T) {
        dataList.add(t)
    }

    fun remove(t: T) {
        dataList.remove(t)
    }

    val data: List<T>
        get() = dataList

    fun getItem(position: Int): T {
        return dataList[position]
    }

    fun setItemClickListener(listener: OnItemClickListener?) {
        onItemClickListener = listener
    }

    interface OnItemClickListener {
        fun onItemClick(view: View, holder: ViewHolder, position: Int)

        fun onItemLongClick(view: View, holder: ViewHolder, position: Int): Boolean
    }

    private fun isHeaderViewPos(position: Int): Boolean {
        return position < headersCount
    }

    private fun isFooterViewPos(position: Int): Boolean {
        return position >= headersCount + (if (isEmpty) 1 else realItemCount)
    }

    protected val isEmpty: Boolean
        get() = (emptyView != null || emptyId != 0) && this.realItemCount == 0

    fun addHeaderView(view: View?) {
        if (view == null) {
            return
        }
        checkViewParent(view)
        headerViews.put(headerViews.size() + BASE_ITEM_TYPE_HEADER, view)
    }

    fun addFootView(view: View?) {
        if (view == null) {
            return
        }
        checkViewParent(view)
        footViews.put(footViews.size() + BASE_ITEM_TYPE_FOOTER, view)
    }

    fun setEmptyView(view: View?) {
        if (view == null) {
            return
        }
        checkViewParent(view)
        emptyView = view
    }

    fun setEmptyView(@LayoutRes emptyId: Int) {
        this.emptyId = emptyId
    }

    private fun checkViewParent(view: View) {
        if (view.parent != null) {
            val parent = view.parent as ViewGroup
            parent.removeView(view)
        }
    }

    val headersCount: Int
        get() = headerViews.size()

    val footersCount: Int
        get() = footViews.size()

    private val realItemCount: Int
        get() = dataList.size

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        WrapperUtils.onAttachedToRecyclerView(
            this,
            recyclerView,
            object : WrapperUtils.SpanSizeCallback {
                override fun getSpanSize(
                    layoutManager: GridLayoutManager,
                    oldLookup: GridLayoutManager.SpanSizeLookup?,
                    position: Int
                ): Int {
                    val viewType = getItemViewType(position)
                    if (headerViews[viewType] != null) {
                        return layoutManager.spanCount
                    } else if (footViews[viewType] != null) {
                        return layoutManager.spanCount
                    } else if (isEmpty) {
                        return layoutManager.spanCount
                    }
                    if (oldLookup != null) {
                        return oldLookup.getSpanSize(position)
                    }
                    return 1
                }
            })
    }

    override fun onViewAttachedToWindow(holder: ViewHolder) {
        val position = holder.layoutPosition
        if (isHeaderViewPos(position) || isFooterViewPos(position)) {
            WrapperUtils.setFullSpan(holder)
        } else if (isEmpty) {
            WrapperUtils.setFullSpan(holder)
        } else {
            providerManager.getProvider(holder.itemViewType).onViewAttachedToWindow(holder)
        }
    }

    override fun onViewDetachedFromWindow(holder: ViewHolder) {
        super.onViewDetachedFromWindow(holder)
        providerManager.getProvider(holder.itemViewType).onViewDetachedFromWindow(holder)
    }

    override fun onViewRecycled(holder: ViewHolder) {
        super.onViewRecycled(holder)
        providerManager.getProvider(holder.itemViewType).onViewDetachedFromWindow(holder)
    }

    companion object {
        private const val BASE_ITEM_TYPE_HEADER = -300
        private const val BASE_ITEM_TYPE_FOOTER = -400
    }
}
