import { useCallback, useEffect, useMemo, useState } from 'react'; import { sortStoryOptionsByPriority } from '../data/stateFunctions'; import { annotateStoryOptionsWithGoalAffordance } from '../services/storyEngine/goalDirector'; import type { GoalStackState, StoryMoment } from '../types'; const OPTION_PAGE_SIZE = 3; export function useStoryOptions( currentStory: StoryMoment | null, goalStack?: GoalStackState | null, ) { const [optionWindowStart, setOptionWindowStart] = useState(0); const activeOptionPool = useMemo(() => { if (!currentStory) { return []; } return sortStoryOptionsByPriority( annotateStoryOptionsWithGoalAffordance( currentStory.options, goalStack, ), ); }, [currentStory, goalStack]); const optionPoolSignature = useMemo( () => activeOptionPool .map((option) => [ option.functionId, option.actionText, option.text ?? '', option.goalAffordance?.goalId ?? '', option.goalAffordance?.relation ?? '', ].join('::'), ) .join('||'), [activeOptionPool], ); useEffect(() => { setOptionWindowStart(0); }, [currentStory, optionPoolSignature]); const displayedOptions = useMemo( () => { const windowOptions = activeOptionPool.slice( optionWindowStart, optionWindowStart + OPTION_PAGE_SIZE, ); if ( windowOptions.some( (option) => option.goalAffordance?.relation === 'advance', ) ) { return windowOptions; } const pinnedAdvanceOption = activeOptionPool.find( (option) => option.goalAffordance?.relation === 'advance', ) ?? null; if (!pinnedAdvanceOption) { return windowOptions; } return [ pinnedAdvanceOption, ...windowOptions .filter( (option) => !( option.functionId === pinnedAdvanceOption.functionId && option.actionText === pinnedAdvanceOption.actionText ), ) .slice(0, OPTION_PAGE_SIZE - 1), ]; }, [activeOptionPool, optionWindowStart], ); const canRefreshOptions = activeOptionPool.length > OPTION_PAGE_SIZE; const handleRefreshOptions = useCallback(() => { if (activeOptionPool.length <= OPTION_PAGE_SIZE) return; const nextStart = optionWindowStart + OPTION_PAGE_SIZE; if (nextStart < activeOptionPool.length) { setOptionWindowStart(nextStart); return; } setOptionWindowStart(0); }, [activeOptionPool.length, optionWindowStart]); const resetStoryOptions = useCallback(() => { setOptionWindowStart(0); }, []); return { activeOptionPool, displayedOptions, optionWindowStart, canRefreshOptions, handleRefreshOptions, resetStoryOptions, }; }