package com.adealink.weparty.commonui.widget.nestedscrolling

import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import androidx.core.view.NestedScrollingParent3
import androidx.core.view.NestedScrollingParentHelper
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.RecyclerView
import com.adealink.weparty.commonui.viewmodel.WEUIViewModelFactory
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import kotlin.math.abs

/**
 * 处理RecyclerView 套viewPager， viewPager内的fragment中 也有RecyclerView，处理外层、内层 RecyclerView的嵌套滑动问题
 * 类似淘宝、京东首页
 */
class NestedScrollingLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
) :
    FrameLayout(context, attrs, defStyleAttr), NestedScrollingParent3 {

    /**
     * 嵌套滑动的父SmartRefreshLayout
     */
    private var parentSmartRefreshLayout: SmartRefreshLayout? = null

    /**
     * 嵌套滑动的父RecyclerView
     */
    private var parentRecyclerView: RecyclerView? = null

    /**
     * 嵌套滑动的子RecyclerView
     */
    private var childRecyclerView: RecyclerView? = null

    /**
     * 外层RecyclerView的最后一个item，即：tab + viewPager
     * 用于判断 滑动 临界位置
     */
    private var lastItemView: View? = null
    /**
     * 特殊场景，可能顶部会有内间距，默认为0即可
     */
    private var topPadding: Int = 0

    private val nestedScrollingParentHelper = NestedScrollingParentHelper(this)
    private var nestedScrollViewModel: NestedScrollViewModel? = null

    fun setTarget(target: LifecycleOwner?) {
        nestedScrollViewModel = when (target) {
            is FragmentActivity -> {
                ViewModelProvider(target, WEUIViewModelFactory())[NestedScrollViewModel::class.java]
            }
            is Fragment -> {
                ViewModelProvider(target, WEUIViewModelFactory())[NestedScrollViewModel::class.java]
            }
            else -> {
                throw IllegalArgumentException("target must be FragmentActivity or Fragment")
            }
        }
        nestedScrollViewModel?.apply {
            childRecyclerViewLD.observe(target, Observer {
                childRecyclerView = it
            })
            lastItemLD.observe(target, Observer {
                lastItemView = it
            })
        }
    }

    /**
     * 有嵌套滑动到来了，判断父view是否接受嵌套滑动
     *
     * @param child            嵌套滑动对应的父类的子类(因为嵌套滑动对于的父View不一定是一级就能找到的，可能挑了两级父View的父View，child的辈分>=target)
     * @param target           具体嵌套滑动的那个子类
     * @param nestedScrollAxes 支持嵌套滚动轴。水平方向，垂直方向，或者不指定
     * @param type             滑动类型，ViewCompat.TYPE_NON_TOUCH fling 效果ViewCompat.TYPE_TOUCH 手势滑动
     */
    override fun onStartNestedScroll(
        child: View,
        target: View,
        nestedScrollAxes: Int,
        type: Int,
    ): Boolean {
        //这里处理是接受 竖向的 嵌套滑动
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
    }

    override fun onNestedScrollAccepted(child: View, target: View, axes: Int, type: Int) {
        nestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes, type)
    }

    /**
     * 在嵌套滑动的子View未滑动之前，判断父view是否优先与子view处理(也就是父view可以先消耗，然后给子view消耗）
     *
     * @param target   具体嵌套滑动的那个子类，就是手指滑的那个 产生嵌套滑动的view
     * @param dx       水平方向嵌套滑动的子View想要变化的距离
     * @param dy       垂直方向嵌套滑动的子View想要变化的距离 dy<0向下滑动 dy>0 向上滑动
     * @param consumed 这个参数要我们在实现这个函数的时候指定，回头告诉子View当前父View消耗的距离
     * consumed[0] 水平消耗的距离，consumed[1] 垂直消耗的距离 好让子view做出相应的调整
     * @param type     滑动类型，ViewCompat.TYPE_NON_TOUCH fling 效果ViewCompat.TYPE_TOUCH 手势滑动
     */
    override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {
        val lastItemTop = lastItemView?.top ?: return
        if (target === parentRecyclerView) {
            onParentScrolling(lastItemTop, dy, consumed)
        } else if (target === childRecyclerView) {
            onChildScrolling(lastItemTop, dy, consumed)
        } else if (target == parentSmartRefreshLayout) {
            //最外层recyclerView有SmartRefreshLayout要特殊处理
            onParentSmartRefreshLayoutScrolling(lastItemTop, dy, consumed)
        }
    }

    /**
     * 滑动外层RecyclerView时，的处理
     *
     * @param lastItemTop tab到屏幕顶部的距离，是0就代表到顶了
     * @param dy          目标滑动距离， dy>0 代表向上滑
     * @param consumed
     */
    private fun onParentScrolling(lastItemTop: Int, dy: Int, consumed: IntArray) {

        if (lastItemTop == topPadding) {
            //列表已置顶
            if (dy > 0) {
                //上滑
                childRecyclerView?.scrollBy(0, dy)
                consumed[1] = dy
            } else {
                if (childRecyclerView?.canScrollVertically(dy) == true) {
                    consumed[1] = dy
                    childRecyclerView?.scrollBy(0, dy)
                }
            }
        } else {
            //列表未置顶
            if (lastItemTop < dy) {
                consumed[1] = dy - lastItemTop
            }
        }
    }

    /**
     * 滑动内层RecyclerView时，的处理
     *
     * @param lastItemTop tab到屏幕顶部的距离，是0就代表到顶了
     * @param dy
     * @param consumed
     */
    private fun onChildScrolling(lastItemTop: Int, dy: Int, consumed: IntArray) {

        if (lastItemTop == topPadding) {
            //列表已置顶
            if (dy < 0) {
                //下滑
                val childScrolledY = childRecyclerView?.computeVerticalScrollOffset() ?: 0
                if (childScrolledY < abs(dy)) {
                    //内层已滚动的距离，小于想要滚动的距离，那么内层消费一部分，到顶后，剩的外层滑动
                    childRecyclerView?.scrollBy(0, -childScrolledY)
                    parentRecyclerView?.scrollBy(0, -(abs(dy) - childScrolledY))
                    consumed[1] = dy
                }
            }
        } else {
            if (dy < 0) {
                if (parentSmartRefreshLayout != null) {
                    val canScroll = parentRecyclerView?.canScrollVertically(dy) ?: true

                    if (!canScroll) {
                        parentSmartRefreshLayout?.closeHeaderOrFooter()
                        return
                    }
                    consumed[1] = dy
                    parentRecyclerView?.scrollBy(0, dy)
                } else {
                    consumed[1] = dy
                    parentRecyclerView?.scrollBy(0, dy)
                }
            } else if (dy in 1 until lastItemTop) {
                consumed[1] = dy
                parentRecyclerView?.scrollBy(0, dy)
            } else {
                //tab的top<=想要滑动的dy,先滑外层，消耗距离为lastItemTop，刚好到顶；剩下的就滑内层了。
                parentRecyclerView?.scrollBy(0, lastItemTop)
                consumed[1] = dy - lastItemTop
            }
        }
    }

    private fun onParentSmartRefreshLayoutScrolling(lastItemTop: Int, dy: Int, consumed: IntArray) {

        if (lastItemTop == topPadding) {
            //列表已置顶
            if (dy < 0) {
                //下滑
                val childScrolledY = childRecyclerView?.computeVerticalScrollOffset() ?: 0
                if (childScrolledY < abs(dy)) {
                    //内层已滚动的距离，小于想要滚动的距离，那么内层消费一部分，到顶后，剩的外层滑动
                    childRecyclerView?.scrollBy(0, -childScrolledY)
                    parentRecyclerView?.scrollBy(0, -(abs(dy) - childScrolledY))
                    consumed[1] = dy
                }
            }
        } else {
            if (dy < 0 || lastItemTop > dy) {
                consumed[1] = dy
                parentRecyclerView?.scrollBy(0, dy)
            } else {
                //tab的top<=想要滑动的dy,先滑外层，消耗距离为lastItemTop，刚好到顶；剩下的就滑内层了。
                parentRecyclerView?.scrollBy(0, lastItemTop)
                consumed[1] = dy - lastItemTop
            }
        }
    }

    override fun onNestedScroll(
        target: View,
        dxConsumed: Int,
        dyConsumed: Int,
        dxUnconsumed: Int,
        dyUnconsumed: Int,
        type: Int,
        consumed: IntArray,
    ) {

    }

    override fun onNestedScroll(
        target: View,
        dxConsumed: Int,
        dyConsumed: Int,
        dxUnconsumed: Int,
        dyUnconsumed: Int,
        type: Int,
    ) {

    }

    override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {
        return false
    }

    override fun onNestedFling(
        target: View,
        velocityX: Float,
        velocityY: Float,
        consumed: Boolean,
    ): Boolean {
        return false
    }

    override fun onStopNestedScroll(target: View, type: Int) {
        nestedScrollingParentHelper.onStopNestedScroll(target, type)
    }

    /**
     * 设置嵌套滑动的外部RecyclerView
     */
    fun setParentRecyclerView(
        parentRecyclerView: RecyclerView?,
        parentSmartRefreshLayout: SmartRefreshLayout? = null,
    ) {
        this.parentRecyclerView = parentRecyclerView
        this.parentSmartRefreshLayout = parentSmartRefreshLayout
    }

    fun setTopPadding(paddingTop:Int){
        this.topPadding=paddingTop
    }

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