/**
 * History Slice - 历史记录管理
 */
import { debounce } from 'lodash-es';
import { CanvasState, CanvasStateSnapshot, MAX_HISTORY_SIZE, SAVE_HISTORY_DELAY } from './types';
import { IncrementalHistory } from '@/lib/utils/historyDiff';
import { SmartHistoryMerger } from '@/lib/utils/historyMerge';

export const createHistoryActions = (set: any, get: any) => ({
    setGenerationHistory: (updater: any[] | ((prev: any[]) => any[])) => set((state: CanvasState) => {
        state.generationHistory = typeof updater === 'function' ? updater(state.generationHistory) : updater;
    }),

    addGenerationHistoryItem: (item: any) => set((state: CanvasState) => {
        state.generationHistory.unshift(item);
    }),

    saveHistory: () => {
        const { nodes, edges, groups, incrementalHistory, memoryMonitoringEnabled } = get();

        if (!incrementalHistory) {
            set((state: CanvasState) => {
                state.incrementalHistory = new IncrementalHistory<CanvasStateSnapshot>(
                    { nodes, edges, groups },
                    { maxHistory: MAX_HISTORY_SIZE, snapshotInterval: 10 }
                );
            });

            if (memoryMonitoringEnabled) {
                get().updateMemoryStats();
            }
            return;
        }

        const { historyMerger } = get();
        if (historyMerger) {
            historyMerger.commitPendingOperation();
        }

        const currentState: CanvasStateSnapshot = { nodes, edges, groups };
        const saved = incrementalHistory.saveState(currentState);

        if (saved && memoryMonitoringEnabled) {
            get().updateMemoryStats();
        }
    },

    saveHistoryWithMerge: (operation?: { type: string; nodeId?: string; data: any }) => {
        const { historyMerger, incrementalHistory } = get();

        if (!historyMerger) {
            set((state: CanvasState) => {
                state.historyMerger = new SmartHistoryMerger({
                    mergeWindow: 1000,
                    mergeableTypes: ['node-move', 'node-resize', 'text-edit'],
                    onCommit: () => {
                        const { nodes, edges, groups, incrementalHistory } = get();

                        if (!incrementalHistory) {
                            set((state: CanvasState) => {
                                state.incrementalHistory = new IncrementalHistory<CanvasStateSnapshot>(
                                    { nodes, edges, groups },
                                    { maxHistory: MAX_HISTORY_SIZE, snapshotInterval: 10 }
                                );
                            });
                        } else {
                            const currentState: CanvasStateSnapshot = { nodes, edges, groups };
                            incrementalHistory.saveState(currentState);
                        }
                    }
                });
            });

            if (operation) {
                const newMerger = get().historyMerger;
                if (newMerger) {
                    newMerger.addOperation(operation);
                }
            }
            return;
        }

        if (operation) {
            historyMerger.addOperation(operation);
        } else {
            historyMerger.commitPendingOperation();
            get().saveHistory();
        }
    },

    commitPendingHistory: () => {
        const { historyMerger } = get();
        if (historyMerger) {
            historyMerger.commitPendingOperation();
        }
    },

    saveHistoryThrottled: () => {
        const { saveHistoryTimeout } = get();

        if (saveHistoryTimeout) {
            clearTimeout(saveHistoryTimeout);
        }

        const newTimeout = setTimeout(() => {
            get().saveHistory();
            set({ saveHistoryTimeout: null } as any);
        }, SAVE_HISTORY_DELAY);

        set({ saveHistoryTimeout: newTimeout } as any);
    },

    undo: () => {
        const { incrementalHistory, historyMerger, memoryMonitoringEnabled } = get();

        if (historyMerger) {
            historyMerger.commitPendingOperation();
        }

        if (!incrementalHistory || !incrementalHistory.canUndo()) {
            return;
        }

        const previousState = incrementalHistory.undo();

        if (previousState) {
            set((state: CanvasState) => {
                state.nodes = previousState.nodes;
                state.edges = previousState.edges;
                state.groups = previousState.groups;
                state.isDirty = true;
            });

            if (memoryMonitoringEnabled) {
                get().updateMemoryStats();
            }
        }
    },

    redo: () => {
        const { incrementalHistory, historyMerger, memoryMonitoringEnabled } = get();

        if (historyMerger) {
            historyMerger.commitPendingOperation();
        }

        if (!incrementalHistory || !incrementalHistory.canRedo()) {
            return;
        }

        const nextState = incrementalHistory.redo();

        if (nextState) {
            set((state: CanvasState) => {
                state.nodes = nextState.nodes;
                state.edges = nextState.edges;
                state.groups = nextState.groups;
                state.isDirty = true;
            });

            if (memoryMonitoringEnabled) {
                get().updateMemoryStats();
            }
        }
    },

    canUndo: () => {
        const { incrementalHistory } = get();
        return incrementalHistory ? incrementalHistory.canUndo() : false;
    },

    canRedo: () => {
        const { incrementalHistory } = get();
        return incrementalHistory ? incrementalHistory.canRedo() : false;
    },

    getHistoryStats: () => {
        const { incrementalHistory } = get();
        return incrementalHistory ? incrementalHistory.getStatistics() : null;
    },

    updateMemoryStats: debounce(() => {
        const { incrementalHistory, memoryMonitoringEnabled } = get();

        if (!memoryMonitoringEnabled || !incrementalHistory) {
            return;
        }

        const stats = incrementalHistory.getStatistics();
        const memoryBytes = stats.memoryUsageBytes;

        set((state: CanvasState) => {
            state.memoryStats = {
                historyMemoryBytes: memoryBytes,
                historyMemoryKB: (memoryBytes / 1024).toFixed(2),
                historyMemoryMB: (memoryBytes / (1024 * 1024)).toFixed(2),
                totalSteps: stats.totalSteps,
                snapshotCount: stats.snapshotCount,
                patchCount: stats.patchCount,
                averageBytesPerStep: stats.totalSteps > 0 ? Math.round(memoryBytes / stats.totalSteps) : 0,
                timestamp: Date.now()
            };
        });
    }, 500),

    getMemoryStats: () => {
        const { memoryStats } = get();
        return memoryStats;
    },

    enableMemoryMonitoring: () => {
        set((state: CanvasState) => {
            state.memoryMonitoringEnabled = true;
        });
        get().updateMemoryStats();
    },

    disableMemoryMonitoring: () => {
        set((state: CanvasState) => {
            state.memoryMonitoringEnabled = false;
            state.memoryStats = null;
        });
    },

    getMemoryReport: () => {
        const { memoryStats, incrementalHistory } = get();

        if (!memoryStats || !incrementalHistory) {
            return 'Memory monitoring is not enabled or no history available.';
        }

        const historyStats = incrementalHistory.getStatistics();

        return `
Canvas History Memory Report
============================
Generated: ${new Date(memoryStats.timestamp).toLocaleString()}

Memory Usage:
  - Total: ${memoryStats.historyMemoryKB} KB (${memoryStats.historyMemoryMB} MB)
  - Average per step: ${memoryStats.averageBytesPerStep} bytes

History Statistics:
  - Total steps: ${memoryStats.totalSteps}
  - Snapshots: ${memoryStats.snapshotCount}
  - Patches: ${memoryStats.patchCount}
  - Current index: ${historyStats.currentIndex}
  - Can undo: ${historyStats.canUndo ? 'Yes' : 'No'}
  - Can redo: ${historyStats.canRedo ? 'Yes' : 'No'}

Efficiency:
  - Snapshot ratio: ${((memoryStats.snapshotCount / memoryStats.totalSteps) * 100).toFixed(1)}%
  - Patch ratio: ${((memoryStats.patchCount / memoryStats.totalSteps) * 100).toFixed(1)}%
        `.trim();
    },
});
