package com.adealink.weparty.module.room.chat.livemessage

import android.content.Context
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.adealink.frame.log.Log
import com.adealink.weparty.commonui.ext.dp
import com.adealink.weparty.commonui.recycleview.adapter.multitype.MultiTypeAdapter
import kotlin.math.max

class LiveMessageRecyclerHelper<T : ILiveMessage>(private var context: Context) {

    //聊天列表，由Activity传过来
    private lateinit var recyclerView: RecyclerView

    //曾经读过的最大的Position
    private var readedMaxIndex = 0L

    //通知Activity还有几条未读消息："底部还有XX条消息"
    var messageRecyclerHelperListener: LiveMessageRecyclerHelperListener? = null

    //正在滚动到底部的动画中
    private var isScrollingToBottom = false

    //由Activity\Fragment 传入RecyclerView
    fun setRecyclerView(recyclerView: RecyclerView) {
        this.recyclerView = recyclerView
        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                //这个回调触发不频繁
                //手指拨动（无论是否发生滚动）newState ：1 -> 2 -> 0 (停下来)
                //代码滚动 newState ：2 -> 0 (停下来)
                //滚动过程中用手指再滚 newState ：2 -> 1（手指摸）-> 2 -> 0 (停下来)
                //滚动过程中用手指按住不然他滚了 newState ：2 -> 1（手指摸）-> 0 (停下来)

                //获取最后一个可见view的位置
                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    //停下来了
                    isScrollingToBottom = false

                    if (isBottom(recyclerView)) {//停在了底部
                        messageRecyclerHelperListener?.onScrollToBottom()
                    }
                } else if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                    //用手指去触摸了
                    isScrollingToBottom = false
                }
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            }
        })
    }

    fun getUnReadCount(): Long {
        val lastItemIndex = getItemByPosition(getItemCount() - 1)?.index() ?: 0
        return max(lastItemIndex - readedMaxIndex, 0)
    }

    fun setMessageAllRead() {
        val lastItemIndex = getItemByPosition(getItemCount() - 1)?.index() ?: 0
        readedMaxIndex = max(lastItemIndex, readedMaxIndex)
        messageRecyclerHelperListener?.unreadMessageCountUpdate(getUnReadCount())
    }

    fun scrollToBottom() {
        Log.d(TAG, "scrollToBottom")
        isScrollingToBottom = true
        recyclerView.layoutManager?.scrollToPosition(max(getItemCount() - 1, 0))
    }

    fun scrollToUnreadPosition() {
        Log.d(TAG, "scrollToUnreadPosition")
        val position = findNextUnReadPosition()
        if (position == null || position < 0) {
            scrollToBottom()
        } else {
            scrollToPosition(position)
        }
    }

    private fun findNextUnReadPosition(): Int? {
        val firstItem = getItemByPosition(0) ?: return null
        val nextIndex = readedMaxIndex + 1
        return if (firstItem.index() > nextIndex) {
            0
        } else {
            findItemPositionByIndex(nextIndex)
        }
    }

    fun scrollToPosition(position: Int) {
        Log.d(TAG, "scrollToPosition, position:$position")
        recyclerView.layoutManager?.scrollToPosition(max(position, 0))
    }

    fun scrollToCurrentReadPosition() {
        Log.d(TAG, "scrollToCurrentReadPosition")
        if (isBottom(recyclerView)) {
            scrollToBottom()
            return
        }
        val position = findCurrentReadPosition()
        if (position == null || position < 0) {
            scrollToBottom()
        } else {
            scrollToPosition(position)
        }
    }

    private fun findCurrentReadPosition(): Int? {
        val firstItem = getItemByPosition(0) ?: return null
        val currentIndex = readedMaxIndex
        return if (firstItem.index() > currentIndex) {
            0
        } else {
            findItemPositionByIndex(currentIndex)
        }
    }

    fun onAdapterItemViewAttached(adapterPosition: Int) {
        val item = getItemByPosition(adapterPosition) ?: return
        val itemIndex = item.index()
        if (readedMaxIndex < itemIndex) {
            readedMaxIndex = itemIndex
            //计算还有几条消息未读，然后回调给Activity
            messageRecyclerHelperListener?.unreadMessageCountUpdate(getUnReadCount())
        }
    }

    private fun findItemPositionByIndex(index: Long): Int? {
        return (recyclerView.adapter as? MultiTypeAdapter)?.items?.indexOfLast { (it as? T)?.index() == index }
    }

    private fun getItemByPosition(position: Int): T? {
        val item = (recyclerView.adapter as? MultiTypeAdapter)?.items?.getOrNull(position) ?: return null
        return item as? T
    }

    private fun getItemCount(): Int {
        return recyclerView.adapter?.itemCount ?: 0
    }

    //notify + 滚到底部。调用该方法前，请先list.add()
    fun notifyAndScrollToBottom(newCount: Int, smooth: Boolean = true) {
        Log.d(TAG, "notifyAndScrollToBottom: newCount:$newCount")
        if (newCount == 0 || recyclerView.adapter == null) {
            return
        }
        if (isBottom(recyclerView, newCount) || isScrollingToBottom) {
            Log.d(TAG, "notifyAndScrollToBottom: scroll")
            //现在就在底部，那么就要滚到底部
            val targetPosition = max(getItemCount() - 1, 0)
            if (targetPosition >= 0) {
                if (smooth) {
                    //如果SmoothScroller设置为全局变量（不是每次都new），那么speed就是固定死的 无法动态调整。且RecyclerView源码还总是打log.e警告
                    val scroller = AdjustLinearSmoothScroller(context, 30.dp())
                    //根据刚刚插入了几条item决定滚动速度，约小约快。这个很难做到完美，因为Item高度不同需要有不同的速度
                    when (newCount) {
                        1 -> scroller.setDuration(300f)
                        2 -> scroller.setDuration(250f)
                        3 -> scroller.setDuration(200f)
                        4 -> scroller.setDuration(100f)
                        5 -> scroller.setDuration(50f)
                        else -> scroller.setDuration(25f)//25f是系统的smoothScrollToPosition的速度
                    }
                    scroller.targetPosition = targetPosition
                    recyclerView.layoutManager?.startSmoothScroll(scroller)
                    isScrollingToBottom = true
                } else {
                    recyclerView.layoutManager?.scrollToPosition(targetPosition)
                }
            }
        } else {
            Log.d(TAG, "notifyAndScrollToBottom: scrolling")
            //计算还有几条消息未读，然后回调给Activity
            messageRecyclerHelperListener?.unreadMessageCountUpdate(getUnReadCount())
        }
    }

    private fun isBottom(recyclerView: RecyclerView, newCount: Int = 0): Boolean {
        val layoutManager = recyclerView.layoutManager as? LinearLayoutManager
        return if (layoutManager != null) {
            //屏幕中最后一个可见子项的position
            val lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition()
            //当前屏幕所看到的子项个数
            val visibleItemCount = layoutManager.childCount
            //当前RecyclerView的所有子项个数
            val totalItemCount = getItemCount()
            //RecyclerView的滑动状态
            val state = recyclerView.scrollState
            visibleItemCount >= 0
                    && state == RecyclerView.SCROLL_STATE_IDLE
                    && lastVisibleItemPosition >= totalItemCount - 3 - max(newCount, 0) //3个差不多一屏消息
        } else {
            recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange()
        }
    }

    interface LiveMessageRecyclerHelperListener {
        //计算还有几条消息未读，然后回调给Activity
        fun unreadMessageCountUpdate(unreadCount: Long)

        fun onScrollToBottom()
    }

    companion object {
        private const val TAG = "LiveMessageRecyclerHelper"
    }
}