import { useEffect, useState, useRef, useMemo } from 'react';
import tokenizeWithMarkdown from '../utils/markdownTokenizer';
import usePrevious from './usePrevious';
const useAnimatedText = ({ text, allContentReceived = false, enabled = true, tokenizeMarkdown = false, cursorStartIndex }) => {
    const initialTokens = 3;
    const maxTokens = 20;
    const phraseSize = 3;
    const [cursor, setCursor] = useState(0); // End pointer
    const [startingCursor, setStartingCursor] = useState(0); // animation starting point
    const [isAnimationDone, setIsAnimationDone] = useState(false);
    const currentSpeedRef = useRef(initialTokens);
    const allContentReceivedRef = useRef(allContentReceived);
    allContentReceivedRef.current = allContentReceived;
    const prevText = usePrevious(text);
    const tokens = useMemo(() => {
        return tokenizeWithMarkdown(text, { tokenizeMarkdown, phraseSize });
    }, [text, tokenizeMarkdown]);
    const visibleText = useMemo(() => {
        return tokens.slice(0, cursor).join('');
    }, [tokens, cursor]);
    useEffect(() => {
        if (cursorStartIndex) {
            setStartingCursor(cursorStartIndex);
        }
    }, []);
    useEffect(() => {
        if (prevText !== undefined && prevText !== text) {
            setIsAnimationDone(false);
            setStartingCursor(text.startsWith(prevText) ? cursor : 0);
        }
    }, [text, cursor, prevText]);
    useEffect(() => {
        // If streaming is disabled or all chunks received - return the whole content
        if (!enabled || allContentReceivedRef.current) {
            setCursor(tokens.length);
            setIsAnimationDone(true);
            currentSpeedRef.current = Math.max(currentSpeedRef.current, maxTokens);
            return;
        }
        const targetLength = tokens.length;
        const charactersToAnimate = targetLength - startingCursor;
        // If there are no more characters to animate
        if (charactersToAnimate <= 0) {
            setCursor(targetLength);
            // Only set animation done if we have all content AND no more characters to animate
            if (allContentReceivedRef.current) {
                setIsAnimationDone(true);
            }
            return;
        }
        let rafId = null;
        let startTime = null;
        let isStopped = false;
        let lastCursor = startingCursor;
        const processTextAnimation = (currentTime) => {
            if (isStopped)
                return;
            // Stop animation immediately when all content is received
            if (allContentReceivedRef.current) {
                setCursor(tokens.length);
                setIsAnimationDone(true);
                currentSpeedRef.current = Math.max(currentSpeedRef.current, maxTokens);
                return;
            }
            // Initialize start time on first frame
            if (startTime === null) {
                startTime = currentTime;
            }
            // Smoothly transition to target speed
            const speedDiff = maxTokens - currentSpeedRef.current;
            currentSpeedRef.current += speedDiff * 0.1; // Smooth transition
            const elapsed = currentTime - startTime;
            const timeStep = elapsed / 1000;
            // Calculate how many tokens we should have shown by now
            const expectedCursor = Math.min(startingCursor + timeStep * currentSpeedRef.current, targetLength);
            const newCursor = Math.min(Math.floor(expectedCursor), targetLength);
            const safeCursor = Math.max(newCursor, lastCursor);
            // Skip update if the cursor is at the same token
            if (safeCursor !== lastCursor) {
                setCursor(safeCursor);
                lastCursor = safeCursor;
            }
            // End condition - stop when we reach the target
            if (safeCursor >= targetLength && allContentReceivedRef.current) {
                setIsAnimationDone(true);
                return;
            }
            // Continue animation if not done
            if (safeCursor < targetLength || !allContentReceivedRef.current) {
                rafId = requestAnimationFrame(processTextAnimation); // Schedule next frame
            }
        };
        // Start the animation
        rafId = requestAnimationFrame(processTextAnimation);
        return () => {
            isStopped = true;
            if (rafId) {
                cancelAnimationFrame(rafId);
            }
        };
    }, [startingCursor, tokens]);
    if (allContentReceived) {
        return {
            text,
            isAnimationDone: true,
            animatedTillCursor: tokens.length
        };
    }
    return {
        text: visibleText,
        isAnimationDone,
        animatedTillCursor: cursor
    };
};
export default useAnimatedText;
//# sourceMappingURL=useAnimatedText.js.map