import { jsx as _jsx } from "react/jsx-runtime";
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { useRef, forwardRef, useImperativeHandle, useCallback, useMemo, useEffect, } from 'react';
import { VirtualizedList, SCROLL_TO_ITEM_END, } from './VirtualizedList.js';
import { useScrollable } from '../../contexts/ScrollProvider.js';
import { Box } from 'ink';
import { useAnimatedScrollbar } from '../../hooks/useAnimatedScrollbar.js';
import { useKeypress } from '../../hooks/useKeypress.js';
import { keyMatchers, Command } from '../../keyMatchers.js';
const ANIMATION_FRAME_DURATION_MS = 33;
function ScrollableList(props, ref) {
    const { hasFocus, width } = props;
    const virtualizedListRef = useRef(null);
    const containerRef = useRef(null);
    useImperativeHandle(ref, () => ({
        scrollBy: (delta) => virtualizedListRef.current?.scrollBy(delta),
        scrollTo: (offset) => virtualizedListRef.current?.scrollTo(offset),
        scrollToEnd: () => virtualizedListRef.current?.scrollToEnd(),
        scrollToIndex: (params) => virtualizedListRef.current?.scrollToIndex(params),
        scrollToItem: (params) => virtualizedListRef.current?.scrollToItem(params),
        getScrollIndex: () => virtualizedListRef.current?.getScrollIndex() ?? 0,
        getScrollState: () => virtualizedListRef.current?.getScrollState() ?? {
            scrollTop: 0,
            scrollHeight: 0,
            innerHeight: 0,
        },
    }), []);
    const getScrollState = useCallback(() => virtualizedListRef.current?.getScrollState() ?? {
        scrollTop: 0,
        scrollHeight: 0,
        innerHeight: 0,
    }, []);
    const scrollBy = useCallback((delta) => {
        virtualizedListRef.current?.scrollBy(delta);
    }, []);
    const { scrollbarColor, flashScrollbar, scrollByWithAnimation } = useAnimatedScrollbar(hasFocus, scrollBy);
    const smoothScrollState = useRef({ active: false, start: 0, from: 0, to: 0, duration: 0, timer: null });
    const stopSmoothScroll = useCallback(() => {
        if (smoothScrollState.current.timer) {
            clearInterval(smoothScrollState.current.timer);
            smoothScrollState.current.timer = null;
        }
        smoothScrollState.current.active = false;
    }, []);
    useEffect(() => stopSmoothScroll, [stopSmoothScroll]);
    const smoothScrollTo = useCallback((targetScrollTop, duration = process.env['NODE_ENV'] === 'test' ? 0 : 200) => {
        stopSmoothScroll();
        const scrollState = virtualizedListRef.current?.getScrollState() ?? {
            scrollTop: 0,
            scrollHeight: 0,
            innerHeight: 0,
        };
        const { scrollTop: startScrollTop, scrollHeight, innerHeight, } = scrollState;
        const maxScrollTop = Math.max(0, scrollHeight - innerHeight);
        let effectiveTarget = targetScrollTop;
        if (targetScrollTop === SCROLL_TO_ITEM_END) {
            effectiveTarget = maxScrollTop;
        }
        const clampedTarget = Math.max(0, Math.min(maxScrollTop, effectiveTarget));
        if (duration === 0) {
            if (targetScrollTop === SCROLL_TO_ITEM_END) {
                virtualizedListRef.current?.scrollTo(SCROLL_TO_ITEM_END);
            }
            else {
                virtualizedListRef.current?.scrollTo(Math.round(clampedTarget));
            }
            flashScrollbar();
            return;
        }
        smoothScrollState.current = {
            active: true,
            start: Date.now(),
            from: startScrollTop,
            to: clampedTarget,
            duration,
            timer: setInterval(() => {
                const now = Date.now();
                const elapsed = now - smoothScrollState.current.start;
                const progress = Math.min(elapsed / duration, 1);
                // Ease-in-out
                const t = progress;
                const ease = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
                const current = smoothScrollState.current.from +
                    (smoothScrollState.current.to - smoothScrollState.current.from) *
                        ease;
                if (progress >= 1) {
                    if (targetScrollTop === SCROLL_TO_ITEM_END) {
                        virtualizedListRef.current?.scrollTo(SCROLL_TO_ITEM_END);
                    }
                    else {
                        virtualizedListRef.current?.scrollTo(Math.round(current));
                    }
                    stopSmoothScroll();
                    flashScrollbar();
                }
                else {
                    virtualizedListRef.current?.scrollTo(Math.round(current));
                }
            }, ANIMATION_FRAME_DURATION_MS),
        };
    }, [stopSmoothScroll, flashScrollbar]);
    useKeypress((key) => {
        if (keyMatchers[Command.SCROLL_UP](key)) {
            stopSmoothScroll();
            scrollByWithAnimation(-1);
            return true;
        }
        else if (keyMatchers[Command.SCROLL_DOWN](key)) {
            stopSmoothScroll();
            scrollByWithAnimation(1);
            return true;
        }
        else if (keyMatchers[Command.PAGE_UP](key) ||
            keyMatchers[Command.PAGE_DOWN](key)) {
            const direction = keyMatchers[Command.PAGE_UP](key) ? -1 : 1;
            const scrollState = getScrollState();
            const current = smoothScrollState.current.active
                ? smoothScrollState.current.to
                : scrollState.scrollTop;
            const innerHeight = scrollState.innerHeight;
            smoothScrollTo(current + direction * innerHeight);
            return true;
        }
        else if (keyMatchers[Command.SCROLL_HOME](key)) {
            smoothScrollTo(0);
            return true;
        }
        else if (keyMatchers[Command.SCROLL_END](key)) {
            smoothScrollTo(SCROLL_TO_ITEM_END);
            return true;
        }
        return false;
    }, { isActive: hasFocus });
    const hasFocusCallback = useCallback(() => hasFocus, [hasFocus]);
    const scrollableEntry = useMemo(() => ({
        // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
        ref: containerRef,
        getScrollState,
        scrollBy: scrollByWithAnimation,
        scrollTo: smoothScrollTo,
        hasFocus: hasFocusCallback,
        flashScrollbar,
    }), [
        getScrollState,
        hasFocusCallback,
        flashScrollbar,
        scrollByWithAnimation,
        smoothScrollTo,
    ]);
    useScrollable(scrollableEntry, true);
    return (_jsx(Box, { ref: containerRef, flexGrow: 1, flexDirection: "column", overflow: "hidden", width: width, children: _jsx(VirtualizedList, { ref: virtualizedListRef, ...props, scrollbarThumbColor: scrollbarColor }) }));
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const ScrollableListWithForwardRef = forwardRef(ScrollableList);
export { ScrollableListWithForwardRef as ScrollableList };
//# sourceMappingURL=ScrollableList.js.map