/**
 * ✔ scroll-x
 * ✔ scroll-y
 * ✔ upper-threshold
 * ✔ lower-threshold
 * ✔ scroll-top
 * ✔ scroll-left
 * ✔ scroll-into-view
 * ✔ scroll-with-animation
 * ✔ enable-back-to-top
 * ✘ enable-passive
 * ✔ refresher-enabled
 * ✔ refresher-threshold(仅自定义下拉节点样式支持)
 * ✔ refresher-default-style(仅 android 支持)
 * ✔ refresher-background(仅 android 支持)
 * ✔ refresher-triggered
 * ✘ enable-flex(scroll-x，rn 默认支持)
 * ✘ scroll-anchoring
 * ✔ paging-enabled
 * ✘ using-sticky
 * ✔ show-scrollbar
 * ✘ fast-deceleration
 * ✔ binddragstart
 * ✔ binddragging
 * ✔ binddragend
 * ✔ bindrefresherrefresh
 * ✘ bindrefresherpulling
 * ✘ bindrefresherrestore
 * ✘ bindrefresherabort
 * ✔ bindscrolltoupper
 * ✔ bindscrolltolower
 * ✔ bindscroll
 */
import { ScrollView, RefreshControl, Gesture, GestureDetector } from 'react-native-gesture-handler';
import { Animated as RNAnimated } from 'react-native';
import { isValidElement, Children, useRef, useState, useEffect, forwardRef, useContext, useMemo, createElement } from 'react';
import Animated, { useSharedValue, withTiming, useAnimatedStyle, runOnJS } from 'react-native-reanimated';
import { warn, hasOwn } from '@mpxjs/utils';
import useInnerProps, { getCustomEvent } from './getInnerListeners';
import useNodesRef from './useNodesRef';
import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, HIDDEN_STYLE, useRunOnJSCallback } from './utils';
import { IntersectionObserverContext, ScrollViewContext } from './context';
import Portal from './mpx-portal';
const AnimatedScrollView = RNAnimated.createAnimatedComponent(ScrollView);
const REFRESH_COLOR = {
    black: ['#000'],
    white: ['#fff']
};
const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
    const { textProps, innerProps: props = {} } = splitProps(scrollViewProps);
    const { enhanced = false, bounces = true, style = {}, binddragstart, binddragging, binddragend, bindtouchmove, 'scroll-x': scrollX = false, 'scroll-y': scrollY = false, 'enable-back-to-top': enableBackToTop = false, 'enable-trigger-intersection-observer': enableTriggerIntersectionObserver = false, 'paging-enabled': pagingEnabled = false, 'upper-threshold': upperThreshold = 50, 'lower-threshold': lowerThreshold = 50, 'scroll-with-animation': scrollWithAnimation = false, 'refresher-enabled': refresherEnabled, 'refresher-default-style': refresherDefaultStyle, 'refresher-background': refresherBackground, 'refresher-threshold': refresherThreshold = 45, 'show-scrollbar': showScrollbar = true, 'scroll-into-view': scrollIntoView = '', 'scroll-top': scrollTop = 0, 'scroll-left': scrollLeft = 0, 'refresher-triggered': refresherTriggered, 'enable-var': enableVar, 'external-var-context': externalVarContext, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'simultaneous-handlers': originSimultaneousHandlers, 'wait-for': waitFor, 'enable-sticky': enableSticky, 'scroll-event-throttle': scrollEventThrottle = 0, 'scroll-into-view-offset': scrollIntoViewOffset = 0, __selectRef } = props;
    const scrollOffset = useRef(new RNAnimated.Value(0)).current;
    const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
    const waitForHandlers = flatGesture(waitFor);
    const { refresherContent, otherContent } = getRefresherContent(props.children);
    const hasRefresher = refresherContent && refresherEnabled;
    const [refreshing, setRefreshing] = useState(false);
    const [enableScroll, setEnableScroll] = useState(true);
    const [scrollBounces, setScrollBounces] = useState(false);
    const enableScrollValue = useSharedValue(true);
    const bouncesValue = useSharedValue(false);
    const translateY = useSharedValue(0);
    const isAtTop = useSharedValue(true);
    const refresherHeight = useSharedValue(0);
    const scrollOptions = useRef({
        contentLength: 0,
        offset: 0,
        scrollLeft: 0,
        scrollTop: 0,
        visibleLength: 0
    });
    const hasCallScrollToUpper = useRef(true);
    const hasCallScrollToLower = useRef(false);
    const initialTimeout = useRef(null);
    const intersectionObservers = useContext(IntersectionObserverContext);
    const firstScrollIntoViewChange = useRef(true);
    const isContentSizeChange = useRef(false);
    const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
    const { textStyle, innerStyle = {} } = splitStyle(normalStyle);
    const scrollViewRef = useRef(null);
    const propsRef = useRef(props);
    const refresherStateRef = useRef({
        hasRefresher,
        refresherTriggered
    });
    propsRef.current = props;
    refresherStateRef.current = {
        hasRefresher,
        refresherTriggered
    };
    const runOnJSCallbackRef = useRef({
        setEnableScroll,
        setScrollBounces,
        setRefreshing,
        onRefresh
    });
    const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
    useNodesRef(props, ref, scrollViewRef, {
        style: normalStyle,
        scrollOffset: scrollOptions,
        node: {
            scrollEnabled: scrollX || scrollY,
            bounces,
            showScrollbar,
            pagingEnabled,
            fastDeceleration: false,
            decelerationDisabled: false,
            scrollTo,
            scrollIntoView: handleScrollIntoView
        },
        gestureRef: scrollViewRef
    });
    const { layoutRef, layoutStyle, layoutProps } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout });
    const contextValue = useMemo(() => {
        return {
            gestureRef: scrollViewRef,
            scrollOffset
        };
    }, []);
    const hasRefresherLayoutRef = useRef(false);
    // layout 完成前先隐藏，避免安卓闪烁问题
    const refresherLayoutStyle = useMemo(() => { return !hasRefresherLayoutRef.current ? HIDDEN_STYLE : {}; }, [hasRefresherLayoutRef.current]);
    const lastOffset = useRef(0);
    if (scrollX && scrollY) {
        warn('scroll-x and scroll-y cannot be set to true at the same time, Mpx will use the value of scroll-y as the criterion');
    }
    useEffect(() => {
        initialTimeout.current = setTimeout(() => {
            scrollToOffset(scrollLeft, scrollTop);
        }, 0);
        return () => {
            initialTimeout.current && clearTimeout(initialTimeout.current);
        };
    }, [scrollTop, scrollLeft]);
    useEffect(() => {
        if (scrollIntoView && __selectRef) {
            if (firstScrollIntoViewChange.current) {
                setTimeout(() => {
                    handleScrollIntoView(scrollIntoView, { offset: scrollIntoViewOffset, animated: scrollWithAnimation });
                });
            }
            else {
                handleScrollIntoView(scrollIntoView, { offset: scrollIntoViewOffset, animated: scrollWithAnimation });
            }
        }
        firstScrollIntoViewChange.current = false;
    }, [scrollIntoView]);
    useEffect(() => {
        if (refresherEnabled) {
            setRefreshing(!!refresherTriggered);
            if (!refresherContent)
                return;
            if (refresherTriggered) {
                translateY.value = withTiming(refresherHeight.value);
                resetScrollState(false);
            }
            else {
                translateY.value = withTiming(0);
                resetScrollState(true);
            }
        }
    }, [refresherTriggered]);
    function scrollTo({ top = 0, left = 0, animated = false, duration }) {
        // 如果指定了 duration 且需要动画，使用自定义动画
        if (animated && duration && duration > 0) {
            // 获取当前滚动位置
            const currentY = scrollOptions.current.scrollTop || 0;
            const currentX = scrollOptions.current.scrollLeft || 0;
            const startTime = Date.now();
            const deltaY = top - currentY;
            const deltaX = left - currentX;
            // 缓动函数：easeInOutCubic
            const easing = (t) => {
                return t < 0.5
                    ? 4 * t * t * t
                    : 1 - Math.pow(-2 * t + 2, 3) / 2;
            };
            // 使用 requestAnimationFrame 实现平滑动画
            const animate = () => {
                const elapsed = Date.now() - startTime;
                const progress = Math.min(elapsed / duration, 1); // 0 到 1
                const easeProgress = easing(progress);
                const nextY = currentY + deltaY * easeProgress;
                const nextX = currentX + deltaX * easeProgress;
                if (scrollViewRef.current) {
                    scrollViewRef.current.scrollTo({ y: nextY, x: nextX, animated: false });
                }
                if (progress < 1) {
                    requestAnimationFrame(animate);
                }
                else {
                    // 确保最终位置准确
                    if (scrollViewRef.current) {
                        scrollViewRef.current.scrollTo({ y: top, x: left, animated: false });
                    }
                }
            };
            requestAnimationFrame(animate);
        }
        else {
            // 使用原生的 scrollTo
            scrollToOffset(left, top, animated);
        }
    }
    function handleScrollIntoView(selector = '', { offset = 0, animated = true, duration = undefined } = {}) {
        try {
            const currentSelectRef = propsRef.current.__selectRef;
            if (!currentSelectRef) {
                const errMsg = '__selectRef is not available. Please ensure the scroll-view component is properly initialized.';
                warn(errMsg);
                return;
            }
            const targetScrollView = scrollViewRef.current;
            if (!targetScrollView) {
                const errMsg = 'scrollViewRef is not ready';
                warn(errMsg);
                return;
            }
            // scroll-into-view prop 按微信规范直传裸 id（如 "section-1"），而 __refs 注册时 key 带 # 或 . 前缀，需补齐才能命中；
            // pageScrollTo 调用方已自带前缀（如 "#section-1"）
            const normalizedSelector = selector.startsWith('#') || selector.startsWith('.') ? selector : `#${selector}`;
            // 调用 __selectRef 查找元素
            const refs = currentSelectRef(normalizedSelector, 'node');
            if (!refs) {
                const errMsg = `Element not found for selector: ${normalizedSelector}`;
                warn(errMsg);
                return;
            }
            const { nodeRef } = refs.getNodeInstance();
            if (!nodeRef?.current) {
                const errMsg = `Node ref not available for selector: ${normalizedSelector}`;
                warn(errMsg);
                return;
            }
            nodeRef.current.measureLayout(targetScrollView, (left, top) => {
                const adjustedLeft = scrollX ? left + offset : left;
                const adjustedTop = scrollY ? top + offset : top;
                // 使用 scrollTo 方法，支持 duration 参数
                if (duration !== undefined) {
                    scrollTo({ left: adjustedLeft, top: adjustedTop, animated, duration });
                }
                else {
                    scrollToOffset(adjustedLeft, adjustedTop, animated);
                }
            }, (error) => {
                warn(`Failed to measure layout for selector ${normalizedSelector}: ${error}`);
            });
        }
        catch (error) {
            const errMsg = `handleScrollIntoView error for selector ${selector}: ${error?.message || error}`;
            warn(errMsg);
        }
    }
    function selectLength(size) {
        return !scrollX ? size.height : size.width;
    }
    function selectOffset(position) {
        return !scrollX ? position.y : position.x;
    }
    function onStartReached(e) {
        const { bindscrolltoupper } = props;
        const { offset } = scrollOptions.current;
        const isScrollingBackward = offset < lastOffset.current;
        if (bindscrolltoupper && (offset <= upperThreshold) && isScrollingBackward) {
            if (!hasCallScrollToUpper.current) {
                bindscrolltoupper(getCustomEvent('scrolltoupper', e, {
                    detail: {
                        direction: scrollX ? 'left' : 'top'
                    },
                    layoutRef
                }, props));
                hasCallScrollToUpper.current = true;
            }
        }
        else {
            hasCallScrollToUpper.current = false;
        }
    }
    function onEndReached(e) {
        const { bindscrolltolower } = props;
        const { contentLength, visibleLength, offset } = scrollOptions.current;
        const distanceFromEnd = contentLength - visibleLength - offset;
        const isScrollingForward = offset > lastOffset.current;
        if (bindscrolltolower && (distanceFromEnd < lowerThreshold) && isScrollingForward) {
            if (!hasCallScrollToLower.current) {
                hasCallScrollToLower.current = true;
                bindscrolltolower(getCustomEvent('scrolltolower', e, {
                    detail: {
                        direction: scrollX ? 'right' : 'bottom'
                    },
                    layoutRef
                }, props));
            }
        }
        else {
            hasCallScrollToLower.current = false;
        }
    }
    function onContentSizeChange(width, height) {
        isContentSizeChange.current = true;
        const newContentLength = selectLength({ height, width });
        const oldContentLength = scrollOptions.current.contentLength;
        scrollOptions.current.contentLength = newContentLength;
        // 内容高度变化时，Animated.event 的映射可能会有不生效的场景，所以需要手动设置一下 scrollOffset 的值
        if (enableSticky && (__mpx_mode__ === 'android' || __mpx_mode__ === 'ios')) {
            // 当内容变少时，检查当前滚动位置是否超出新的内容范围
            if (newContentLength < oldContentLength) {
                const { visibleLength, offset } = scrollOptions.current;
                const maxOffset = Math.max(0, newContentLength - visibleLength);
                // 如果当前滚动位置超出了新的内容范围，调整滚动offset
                if (offset > maxOffset && scrollY) {
                    scrollOffset.setValue(maxOffset);
                }
            }
        }
    }
    function onLayout(e) {
        const layout = e.nativeEvent.layout || {};
        scrollOptions.current.visibleLength = selectLength(layout);
    }
    function updateScrollOptions(e, position) {
        const visibleLength = selectLength(e.nativeEvent.layoutMeasurement);
        const contentLength = selectLength(e.nativeEvent.contentSize);
        const offset = selectOffset(e.nativeEvent.contentOffset);
        extendObject(scrollOptions.current, {
            contentLength,
            offset,
            scrollLeft: position.scrollLeft,
            scrollTop: position.scrollTop,
            visibleLength
        });
    }
    function onScroll(e) {
        const { bindscroll } = props;
        const { contentOffset, layoutMeasurement, contentSize } = e.nativeEvent;
        const { x: scrollLeft, y: scrollTop } = contentOffset;
        const { width: scrollWidth, height: scrollHeight } = contentSize;
        isAtTop.value = scrollTop <= 0;
        bindscroll &&
            bindscroll(getCustomEvent('scroll', e, {
                detail: {
                    scrollLeft,
                    scrollTop,
                    scrollHeight,
                    scrollWidth,
                    deltaX: scrollLeft - scrollOptions.current.scrollLeft,
                    deltaY: scrollTop - scrollOptions.current.scrollTop,
                    layoutMeasurement
                },
                layoutRef
            }, props));
        updateScrollOptions(e, { scrollLeft, scrollTop });
        onStartReached(e);
        onEndReached(e);
        updateIntersection();
        // 在 onStartReached、onEndReached 执行完后更新 lastOffset
        lastOffset.current = scrollOptions.current.offset;
    }
    function onScrollEnd(e) {
        const { bindscrollend } = props;
        const { contentOffset, layoutMeasurement, contentSize } = e.nativeEvent;
        const { x: scrollLeft, y: scrollTop } = contentOffset;
        const { width: scrollWidth, height: scrollHeight } = contentSize;
        isAtTop.value = scrollTop <= 0;
        bindscrollend &&
            bindscrollend(getCustomEvent('scrollend', e, {
                detail: {
                    scrollLeft,
                    scrollTop,
                    scrollHeight,
                    scrollWidth,
                    layoutMeasurement
                },
                layoutRef
            }, props));
        updateScrollOptions(e, { scrollLeft, scrollTop });
        onStartReached(e);
        onEndReached(e);
        updateIntersection();
        lastOffset.current = scrollOptions.current.offset;
    }
    function updateIntersection() {
        if (enableTriggerIntersectionObserver && intersectionObservers) {
            for (const key in intersectionObservers) {
                intersectionObservers[key].throttleMeasure();
            }
        }
    }
    function scrollToOffset(x = 0, y = 0, animated = scrollWithAnimation) {
        if (scrollViewRef.current) {
            scrollViewRef.current.scrollTo({ x, y, animated });
        }
    }
    function onScrollTouchMove(e) {
        bindtouchmove && bindtouchmove(e);
        if (enhanced) {
            binddragging &&
                binddragging(getCustomEvent('dragging', e, {
                    detail: {
                        scrollLeft: scrollOptions.current.scrollLeft || 0,
                        scrollTop: scrollOptions.current.scrollTop || 0
                    },
                    layoutRef
                }, props));
        }
    }
    function onScrollDrag(e) {
        const { x: scrollLeft, y: scrollTop } = e.nativeEvent.contentOffset;
        updateScrollOptions(e, { scrollLeft, scrollTop });
        updateIntersection();
    }
    const scrollHandler = RNAnimated.event([{ nativeEvent: { contentOffset: { y: scrollOffset } } }], {
        useNativeDriver: true,
        listener: (event) => {
            const y = event.nativeEvent.contentOffset.y || 0;
            // 内容高度变化时，鸿蒙中 listener 回调通过scrollOffset.__getValue获取值一直等于event.nativeEvent.contentOffset.y，值是正确的，但是无法触发 sticky 动画执行，所以需要手动再 set 一次
            if (__mpx_mode__ === 'harmony') {
                if (isContentSizeChange.current) {
                    scrollOffset.setValue(y);
                    setTimeout(() => {
                        isContentSizeChange.current = false;
                    }, 100);
                }
            }
            onScroll(event);
        }
    });
    function onScrollDragStart(e) {
        hasCallScrollToLower.current = false;
        hasCallScrollToUpper.current = false;
        onScrollDrag(e);
        if (enhanced) {
            binddragstart &&
                binddragstart(getCustomEvent('dragstart', e, {
                    detail: {
                        scrollLeft: scrollOptions.current.scrollLeft,
                        scrollTop: scrollOptions.current.scrollTop
                    },
                    layoutRef
                }, props));
        }
    }
    function onScrollDragEnd(e) {
        onScrollDrag(e);
        if (enhanced) {
            // 安卓上如果触发了默认的下拉刷新，binddragend可能不触发，只会触发 binddragstart
            binddragend &&
                binddragend(getCustomEvent('dragend', e, {
                    detail: {
                        scrollLeft: scrollOptions.current.scrollLeft || 0,
                        scrollTop: scrollOptions.current.scrollTop || 0
                    },
                    layoutRef
                }, props));
        }
    }
    // 处理刷新
    function onRefresh() {
        const { hasRefresher, refresherTriggered } = refresherStateRef.current;
        if (hasRefresher && refresherTriggered === undefined) {
            // 处理使用了自定义刷新组件，又没设置 refresherTriggered 的情况
            setRefreshing(true);
            setTimeout(() => {
                setRefreshing(false);
                translateY.value = withTiming(0);
                if (!enableScrollValue.value) {
                    resetScrollState(true);
                }
            }, 500);
        }
        const { bindrefresherrefresh } = propsRef.current;
        bindrefresherrefresh &&
            bindrefresherrefresh(getCustomEvent('refresherrefresh', {}, { layoutRef }, propsRef.current));
    }
    function getRefresherContent(children) {
        let refresherContent = null;
        const otherContent = [];
        Children.forEach(children, (child) => {
            if (isValidElement(child) && child.props.slot === 'refresher') {
                refresherContent = child;
            }
            else {
                otherContent.push(child);
            }
        });
        return {
            refresherContent,
            otherContent
        };
    }
    // 刷新控件的动画样式
    const refresherAnimatedStyle = useAnimatedStyle(() => {
        return {
            position: 'absolute',
            left: 0,
            right: 0,
            top: -refresherHeight.value,
            transform: [{ translateY: Math.min(translateY.value, refresherHeight.value) }],
            backgroundColor: refresherBackground || 'transparent'
        };
    });
    // 内容区域的动画样式 - 只有内容区域需要下移
    const contentAnimatedStyle = useAnimatedStyle(() => {
        return {
            transform: [{
                    translateY: translateY.value > refresherHeight.value
                        ? refresherHeight.value
                        : translateY.value
                }]
        };
    });
    function onRefresherLayout(e) {
        const { height } = e.nativeEvent.layout;
        refresherHeight.value = height;
        hasRefresherLayoutRef.current = true;
    }
    function updateScrollState(newValue) {
        'worklet';
        if (enableScrollValue.value !== newValue) {
            enableScrollValue.value = newValue;
            runOnJS(runOnJSCallback)('setEnableScroll', newValue);
        }
    }
    const resetScrollState = (value) => {
        enableScrollValue.value = value;
        setEnableScroll(value);
    };
    function updateBouncesState(newValue) {
        'worklet';
        if (bouncesValue.value !== newValue) {
            bouncesValue.value = newValue;
            runOnJS(runOnJSCallback)('setScrollBounces', newValue);
        }
    }
    // 处理下拉刷新的手势 - 使用 useMemo 避免每次渲染都创建
    const panGesture = useMemo(() => {
        return Gesture.Pan()
            .activeOffsetY([-5, 5])
            .failOffsetX([-5, 5])
            .onUpdate((event) => {
            'worklet';
            if (enhanced && !!bounces) {
                if (event.translationY > 0 && bouncesValue.value) {
                    updateBouncesState(false);
                }
                else if ((event.translationY < 0) && !bouncesValue.value) {
                    updateBouncesState(true);
                }
            }
            if (translateY.value <= 0 && event.translationY < 0) {
                // 滑动到顶再向上开启滚动
                updateScrollState(true);
            }
            else if (event.translationY > 0 && isAtTop.value) {
                // 滚动到顶再向下禁止滚动
                updateScrollState(false);
            }
            // 禁止滚动后切换为滑动
            if (!enableScrollValue.value && isAtTop.value) {
                if (refreshing) {
                    // 从完全展开状态(refresherHeight.value)开始计算偏移
                    translateY.value = Math.max(0, Math.min(refresherHeight.value, refresherHeight.value + event.translationY));
                }
                else if (event.translationY > 0) {
                    // 非刷新状态下的下拉逻辑保持不变
                    translateY.value = Math.min(event.translationY * 0.6, refresherHeight.value);
                }
            }
        })
            .onEnd((event) => {
            'worklet';
            if (enableScrollValue.value)
                return;
            if (refreshing) {
                // 刷新状态下，根据滑动距离决定是否隐藏
                // 如果向下滑动没超过 refresherThreshold，就完全隐藏，如果向上滑动完全隐藏
                if ((event.translationY > 0 && translateY.value < refresherThreshold) || event.translationY < 0) {
                    translateY.value = withTiming(0);
                    updateScrollState(true);
                    runOnJS(runOnJSCallback)('setRefreshing', false);
                }
                else {
                    translateY.value = withTiming(refresherHeight.value);
                }
            }
            else if (event.translationY >= refresherHeight.value) {
                // 触发刷新
                translateY.value = withTiming(refresherHeight.value);
                runOnJS(runOnJSCallback)('onRefresh');
            }
            else {
                // 回弹
                translateY.value = withTiming(0);
                updateScrollState(true);
                runOnJS(runOnJSCallback)('setRefreshing', false);
            }
        })
            .simultaneousWithExternalGesture(scrollViewRef);
    }, [enhanced, bounces, refreshing, refresherThreshold]);
    const scrollAdditionalProps = extendObject({
        style: extendObject(hasOwn(innerStyle, 'flex') || hasOwn(innerStyle, 'flexGrow')
            ? {}
            : {
                flexGrow: 0
            }, innerStyle, layoutStyle),
        pinchGestureEnabled: false,
        alwaysBounceVertical: false,
        alwaysBounceHorizontal: false,
        horizontal: scrollX && !scrollY,
        scrollEventThrottle: scrollEventThrottle,
        scrollsToTop: enableBackToTop,
        showsHorizontalScrollIndicator: scrollX && showScrollbar,
        showsVerticalScrollIndicator: scrollY && showScrollbar,
        scrollEnabled: !enableScroll ? false : !!(scrollX || scrollY),
        bounces: false,
        overScrollMode: 'never',
        ref: scrollViewRef,
        onScroll: enableSticky ? scrollHandler : onScroll,
        onContentSizeChange: onContentSizeChange,
        bindtouchmove: ((enhanced && binddragging) || bindtouchmove) && onScrollTouchMove,
        onScrollBeginDrag: onScrollDragStart,
        onScrollEndDrag: onScrollDragEnd,
        onMomentumScrollEnd: onScrollEnd
    }, (simultaneousHandlers ? { simultaneousHandlers } : {}), (waitForHandlers ? { waitFor: waitForHandlers } : {}), layoutProps);
    if (enhanced) {
        Object.assign(scrollAdditionalProps, {
            bounces: hasRefresher ? scrollBounces : !!bounces,
            pagingEnabled
        });
    }
    const innerProps = useInnerProps(extendObject({}, props, scrollAdditionalProps), [
        'id',
        'scroll-x',
        'scroll-y',
        'enable-back-to-top',
        'enable-trigger-intersection-observer',
        'paging-enabled',
        'show-scrollbar',
        'upper-threshold',
        'lower-threshold',
        'scroll-top',
        'scroll-left',
        'scroll-with-animation',
        'refresher-triggered',
        'refresher-enabled',
        'refresher-default-style',
        'refresher-background',
        'children',
        'enhanced',
        'binddragstart',
        'binddragging',
        'binddragend',
        'bindscroll',
        'bindscrolltoupper',
        'bindscrolltolower',
        'bindrefresherrefresh'
    ], { layoutRef });
    const ScrollViewComponent = enableSticky ? AnimatedScrollView : ScrollView;
    const createScrollViewContent = () => {
        const wrappedChildren = wrapChildren(hasRefresher ? extendObject({}, props, { children: otherContent }) : props, {
            hasVarDec,
            varContext: varContextRef.current,
            textStyle,
            textProps
        });
        return createElement(ScrollViewContext.Provider, { value: contextValue }, wrappedChildren);
    };
    const withRefresherScrollView = () => {
        return createElement(GestureDetector, { gesture: panGesture }, createElement(ScrollViewComponent, innerProps, createElement(Animated.View, { style: [refresherAnimatedStyle, refresherLayoutStyle], onLayout: onRefresherLayout }, refresherContent), createElement(Animated.View, { style: contentAnimatedStyle }, createScrollViewContent())));
    };
    const commonScrollView = () => {
        const refreshControl = refresherEnabled
            ? createElement(RefreshControl, extendObject({
                progressBackgroundColor: refresherBackground,
                refreshing: refreshing,
                onRefresh: onRefresh
            }, refresherDefaultStyle && refresherDefaultStyle !== 'none'
                ? { colors: REFRESH_COLOR[refresherDefaultStyle] }
                : {}))
            : undefined;
        return createElement(ScrollViewComponent, extendObject({}, innerProps, { refreshControl }), createScrollViewContent());
    };
    let scrollViewComponent = hasRefresher ? withRefresherScrollView() : commonScrollView();
    if (hasPositionFixed) {
        scrollViewComponent = createElement(Portal, null, scrollViewComponent);
    }
    return scrollViewComponent;
});
_ScrollView.displayName = 'MpxScrollView';
export default _ScrollView;
