import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { buildGoalStackState, createGoalPulseSnapshot, deriveGoalPulseEvent, } from '../../services/storyEngine/goalDirector'; import type { GameState } from '../../types'; import type { GoalFlowUi } from './uiTypes'; export function useStoryGoalFlow(gameState: GameState) { const [goalPulse, setGoalPulse] = useState(null); const previousGoalPulseSnapshotRef = useRef | null>(null); const runtimeGoalStack = useMemo( () => buildGoalStackState({ quests: gameState.quests, worldType: gameState.worldType, currentSceneId: gameState.currentScenePreset?.id ?? null, chapterState: gameState.chapterState ?? gameState.storyEngineMemory?.currentChapter ?? null, journeyBeat: gameState.storyEngineMemory?.currentJourneyBeat ?? null, setpieceDirective: gameState.storyEngineMemory?.currentSetpieceDirective ?? null, currentCampEvent: gameState.storyEngineMemory?.currentCampEvent ?? null, currentSceneName: gameState.currentScenePreset?.name ?? null, }), [ gameState.chapterState, gameState.currentScenePreset?.id, gameState.currentScenePreset?.name, gameState.quests, gameState.storyEngineMemory?.currentCampEvent, gameState.storyEngineMemory?.currentChapter, gameState.storyEngineMemory?.currentJourneyBeat, gameState.storyEngineMemory?.currentSetpieceDirective, gameState.worldType, ], ); useEffect(() => { const currentSnapshot = createGoalPulseSnapshot( gameState.quests, runtimeGoalStack, ); const previousSnapshot = previousGoalPulseSnapshotRef.current; if (!previousSnapshot) { previousGoalPulseSnapshotRef.current = currentSnapshot; return; } const nextPulse = deriveGoalPulseEvent({ previous: previousSnapshot, quests: gameState.quests, goalStack: runtimeGoalStack, }); if (nextPulse) { setGoalPulse(nextPulse); } previousGoalPulseSnapshotRef.current = currentSnapshot; }, [gameState.quests, runtimeGoalStack]); const dismissGoalPulse = useCallback(() => { setGoalPulse(null); }, []); const resetGoalPulseTracking = useCallback(() => { previousGoalPulseSnapshotRef.current = null; setGoalPulse(null); }, []); return { runtimeGoalStack, goalUi: { goalStack: runtimeGoalStack, pulse: goalPulse, dismissPulse: dismissGoalPulse, } satisfies GoalFlowUi, resetGoalPulseTracking, }; }