package com.adealink.weparty.im.session.widget

import android.content.Context
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator
import com.adealink.frame.log.Log
import com.adealink.frame.util.isMainThread
import com.adealink.frame.util.runOnUiThread
import com.adealink.weparty.im.session.adapter.SessionAdapter
import com.tencent.qcloud.tuikit.timcommon.bean.TUIMessageBean
import com.tencent.qcloud.tuikit.timcommon.component.CustomLinearLayoutManager
import com.tencent.qcloud.tuikit.timcommon.component.scroller.CenteredSmoothScroller
import com.tencent.qcloud.tuikit.tuichat.TUIChatService
import com.tencent.qcloud.tuikit.tuichat.bean.ChatInfo
import com.tencent.qcloud.tuikit.tuichat.interfaces.IMessageRecyclerView
import com.tencent.qcloud.tuikit.tuichat.interfaces.OnEmptySpaceClickListener
import com.tencent.qcloud.tuikit.tuichat.interfaces.OnGestureScrollListener
import com.tencent.qcloud.tuikit.tuichat.presenter.ChatPresenter

class MessageRecyclerView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : RecyclerView(context, attrs, defStyle), IMessageRecyclerView {

    private var chatDelegate: ChatDelegate? = null
    var emptySpaceClickListener: OnEmptySpaceClickListener? = null
    private var onGestureScrollListener: OnGestureScrollListener? = null
    private var mAdapter: SessionAdapter? = null
    private var linearLayoutManager: LinearLayoutManager? = null
    private var presenter: ChatPresenter? = null

    init {
        initView(context, attrs)
    }

    private fun initView(context: Context, attrs: AttributeSet? = null) {
        if (isInEditMode) {
            return
        }
        Log.d(TAG, "init()")
        isLayoutFrozen = false
        setItemViewCacheSize(0)
        setHasFixedSize(true)
        setFocusableInTouchMode(false)
        setFocusable(true)
        isClickable = true
        linearLayoutManager =
            CustomLinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
        setLayoutManager(linearLayoutManager)
        (itemAnimator as SimpleItemAnimator?)?.supportsChangeAnimations = false
        setItemAnimator(null)
        setClickEmptySpaceEvent()
        addOnLayoutChangeListener(object : OnLayoutChangeListener {
            override fun onLayoutChange(
                v: View?,
                left: Int,
                top: Int,
                right: Int,
                bottom: Int,
                oldLeft: Int,
                oldTop: Int,
                oldRight: Int,
                oldBottom: Int
            ) {
                // When the view above the message list expands, scroll down the corresponding distance.
                val oldHeight = oldBottom - oldTop
                val newHeight = bottom - top
                if (oldHeight != 0 && oldHeight > newHeight && oldTop < top) {
                    scrollBy(0, oldHeight - newHeight)
                }
            }
        })
    }

    fun setPresenter(presenter: ChatPresenter?) {
        this.presenter = presenter
    }

    override fun setAdapter(adapter: Adapter<*>?) {
        super.setAdapter(adapter)
        mAdapter = adapter as? SessionAdapter
    }

    private fun setClickEmptySpaceEvent() {
        val gestureListener: GestureDetector.OnGestureListener =
            object : SimpleOnGestureListener() {

                override fun onSingleTapUp(e: MotionEvent): Boolean {
                    return emptySpaceClickListener?.let {
                        it.onClick()
                        true
                    } ?: false
                }

                override fun onDown(e: MotionEvent): Boolean {
                    return false
                }

                override fun onScroll(
                    e1: MotionEvent?,
                    e2: MotionEvent,
                    distanceX: Float,
                    distanceY: Float
                ): Boolean {
                    onGestureScrollListener?.onScroll(e1, e2, distanceX, distanceY)
                    return super.onScroll(e1, e2, distanceX, distanceY)
                }
            }

        val gestureDetector = GestureDetector(context, gestureListener)
        setOnTouchListener(object : OnTouchListener {
            override fun onTouch(v: View?, event: MotionEvent): Boolean {
                if (v is RecyclerView) {
                    gestureDetector.onTouchEvent(event)
                }
                return false
            }
        })
    }

    // Always return last visible item for laying out other items from tail to head.
    override fun getFocusedChild(): View? {
        if (linearLayoutManager != null) {
            val position = linearLayoutManager!!.findLastVisibleItemPosition()
            return linearLayoutManager!!.findViewByPosition(position)
        }
        return super.getFocusedChild()
    }

    fun onMsgAddBack() {
        if (mAdapter != null) {
            if (this.isLastItemVisibleCompleted) {
                scrollToEnd()
            }
        }
    }

    override fun isDisplayJumpMessageLayout(): Boolean {
        Log.d(
            TAG,
            ("computeVerticalScrollRange() = " + computeVerticalScrollRange() + ", computeVerticalScrollExtent() = " + computeVerticalScrollExtent()
                    + ", computeVerticalScrollOffset() = " + computeVerticalScrollOffset())
        )
        val toBottom =
            computeVerticalScrollRange() - computeVerticalScrollExtent() - computeVerticalScrollOffset()
        Log.d(TAG, "toBottom = " + toBottom)
        if (toBottom > 0 && toBottom >= 2 * computeVerticalScrollExtent()) {
            return true
        } else {
            return false
        }
    }

    val isLastItemVisibleCompleted: Boolean
        get() {
            val linearLayoutManager =
                getLayoutManager() as LinearLayoutManager?
            if (linearLayoutManager == null) {
                return false
            }
            val lastPosition =
                linearLayoutManager.findLastCompletelyVisibleItemPosition()
            val childCount = linearLayoutManager.getChildCount()
            val firstPosition = linearLayoutManager.findFirstVisibleItemPosition()
            if (lastPosition >= firstPosition + childCount - 1) {
                return true
            }
            return false
        }

    private fun isDefaultMessage(messageBean: TUIMessageBean): Boolean {
        val extensionMessageClassSet = TUIChatService.getInstance().getExtensionMessageClassSet()
        return !extensionMessageClassSet.contains(messageBean.javaClass)
    }

    override fun displayBackToNewMessage(display: Boolean, messageId: String?, count: Int) {
        if (chatDelegate != null) {
            chatDelegate!!.displayBackToNewMessage(display, messageId, count)
        }
    }

    override fun scrollToEnd() {
        if (!isMainThread()) {
            runOnUiThread {
                scrollToEnd()
            }
            return
        }

        adapter?.let { adapter ->
            val layoutManager = getLayoutManager()
            val itemCount = adapter.itemCount
            if (layoutManager is LinearLayoutManager && itemCount > 0) {
                layoutManager.scrollToPositionWithOffset(itemCount - 1, SCROLL_TO_END_OFFSET)
            }
        }
    }

    override fun smoothScrollToPosition(position: Int) {
        val adapter = adapter ?: return
        if (position < adapter.itemCount) {
            val smoothScroller = CenteredSmoothScroller(context)
            smoothScroller.targetPosition = position
            layoutManager?.startSmoothScroll(smoothScroller)
        }
    }

    fun setChatDelegate(chatDelegate: ChatDelegate?) {
        this.chatDelegate = chatDelegate
    }

    fun setOnGestureScrollListener(onGestureScrollListener: OnGestureScrollListener?) {
        this.onGestureScrollListener = onGestureScrollListener
    }

    fun loadMessageFinish() {
        chatDelegate?.loadMessageFinish()
    }

    fun scrollMessageFinish() {
        chatDelegate?.scrollMessageFinish()
    }

    private val chatInfo: ChatInfo?
        get() = presenter?.chatInfo

    var onVisibilityChanged: ((
        visibility: Int,
        findFirstCompletelyVisibleItemPosition: Int,
        findLastCompletelyVisibleItemPosition: Int
    ) -> Unit)? = null

    override fun onVisibilityChanged(changedView: View, visibility: Int) {
        // You will go to Chat from other interfaces, and you must also report a read receipt
        if (visibility == VISIBLE) {
            val linearLayoutManager = linearLayoutManager
            if (linearLayoutManager == null) {
                return
            }
            val firstVisiblePosition = linearLayoutManager.findFirstCompletelyVisibleItemPosition()
            val lastVisiblePosition = linearLayoutManager.findLastCompletelyVisibleItemPosition()
            onVisibilityChanged?.invoke(visibility, firstVisiblePosition, lastVisiblePosition)
        }
    }

    interface ChatDelegate {
        fun displayBackToLastMessage(display: Boolean)

        fun displayBackToNewMessage(display: Boolean, messageId: String?, count: Int)

        fun loadMessageFinish()

        fun scrollMessageFinish()

        fun hideSoftInput()
    }

    companion object {
        private val TAG: String = MessageRecyclerView::class.java.getSimpleName()

        // Take a large enough offset to scroll to the bottom at one time
        private const val SCROLL_TO_END_OFFSET = -999999
    }
}
