import { create } from 'zustand'; import type { Command, HistoryState } from '@/types/history'; interface HistoryStore extends HistoryState { /** Execute a command and add to history */ executeCommand: (command: Command) => void; /** Undo the last command */ undo: () => void; /** Redo the last undone command */ redo: () => void; /** Clear all history */ clearHistory: () => void; /** Check if can undo */ canUndo: () => boolean; /** Check if can redo */ canRedo: () => boolean; /** Get current state summary */ getHistorySummary: () => { undoCount: number; redoCount: number }; } const MAX_HISTORY_SIZE = 50; export const useHistoryStore = create((set, get) => ({ undoStack: [], redoStack: [], maxHistorySize: MAX_HISTORY_SIZE, isExecuting: false, executeCommand: (command) => { const state = get(); // Prevent recursive execution if (state.isExecuting) return; set({ isExecuting: true }); try { // Try to merge with last command const lastCommand = state.undoStack[state.undoStack.length - 1]; if (lastCommand && lastCommand.merge && lastCommand.merge(command)) { // Command was merged, re-execute the merged command lastCommand.execute(); set({ isExecuting: false }); return; } // Execute the new command command.execute(); // Add to undo stack const newUndoStack = [...state.undoStack, command]; // Limit stack size if (newUndoStack.length > state.maxHistorySize) { newUndoStack.shift(); } set({ undoStack: newUndoStack, redoStack: [], // Clear redo stack on new action isExecuting: false, }); } catch (error) { console.error('Failed to execute command:', error); set({ isExecuting: false }); } }, undo: () => { const state = get(); if (state.undoStack.length === 0 || state.isExecuting) return; set({ isExecuting: true }); try { const command = state.undoStack[state.undoStack.length - 1]; command.undo(); set({ undoStack: state.undoStack.slice(0, -1), redoStack: [...state.redoStack, command], isExecuting: false, }); } catch (error) { console.error('Failed to undo command:', error); set({ isExecuting: false }); } }, redo: () => { const state = get(); if (state.redoStack.length === 0 || state.isExecuting) return; set({ isExecuting: true }); try { const command = state.redoStack[state.redoStack.length - 1]; command.execute(); set({ undoStack: [...state.undoStack, command], redoStack: state.redoStack.slice(0, -1), isExecuting: false, }); } catch (error) { console.error('Failed to redo command:', error); set({ isExecuting: false }); } }, clearHistory: () => { set({ undoStack: [], redoStack: [], }); }, canUndo: () => { return get().undoStack.length > 0; }, canRedo: () => { return get().redoStack.length > 0; }, getHistorySummary: () => { const state = get(); return { undoCount: state.undoStack.length, redoCount: state.redoStack.length, }; }, }));