/**
 * Simple Undo/Redo Hook for Builder State
 * Based on Memento pattern - stores complete state snapshots
 */

import { useState, useCallback, useEffect } from 'react';
import type { BuilderState } from './context';

function cloneState<T>(value: T): T {
  if (typeof structuredClone === 'function') {
    return structuredClone(value);
  }

  return JSON.parse(JSON.stringify(value)) as T;
}

interface UndoRedoHook {
  canUndo: boolean;
  canRedo: boolean;
  undo: () => void;
  redo: () => void;
  store: () => void; // Save current state to undo stack
  clear: () => void;
}

export function useSimpleUndoRedo(
  currentState: BuilderState,
  onStateChange: (state: BuilderState) => void,
  maxHistorySize: number = 50
): UndoRedoHook {
  const [undoStack, setUndoStack] = useState<BuilderState[]>([]);
  const [redoStack, setRedoStack] = useState<BuilderState[]>([]);

  const canUndo = undoStack.length > 0;
  const canRedo = redoStack.length > 0;

  const store = useCallback(() => {
    // Deep clone the state to prevent mutations
    const stateSnapshot = cloneState(currentState);
    
    setUndoStack(prev => {
      const newStack = [...prev, stateSnapshot];
      
      // Limit history size
      if (newStack.length > maxHistorySize) {
        return newStack.slice(-maxHistorySize);
      }
      
      return newStack;
    });
    
    // Clear redo stack when new state is stored
    setRedoStack([]);
  }, [currentState, maxHistorySize]);

  const undo = useCallback(() => {
    if (!canUndo) return;

    const lastState = undoStack[undoStack.length - 1];

    // Move current state to redo stack
    const currentSnapshot = cloneState(currentState);
    setRedoStack(prev => [...prev, currentSnapshot]);
    
    // Remove last state from undo stack
    setUndoStack(prev => prev.slice(0, prev.length - 1));
    
    // Apply the previous state
    onStateChange(lastState);
  }, [canUndo, undoStack, currentState, onStateChange]);

  const redo = useCallback(() => {
    if (!canRedo) return;

    const lastRedoState = redoStack[redoStack.length - 1];

    // Move current state to undo stack
    const currentSnapshot = cloneState(currentState);
    setUndoStack(prev => [...prev, currentSnapshot]);
    
    // Remove last state from redo stack
    setRedoStack(prev => prev.slice(0, prev.length - 1));
    
    // Apply the redo state
    onStateChange(lastRedoState);
  }, [canRedo, redoStack, currentState, onStateChange]);

  const clear = useCallback(() => {
    setUndoStack([]);
    setRedoStack([]);
  }, []);

  // Keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      // Only handle shortcuts when not in input elements
      const target = event.target as HTMLElement;
      if (
        target.tagName === 'INPUT' ||
        target.tagName === 'TEXTAREA' ||
        target.tagName === 'SELECT' ||
        target.contentEditable === 'true'
      ) {
        return;
      }

      const isCtrlOrCmd = event.ctrlKey || event.metaKey;

      if (isCtrlOrCmd && event.key === 'z') {
        event.preventDefault();
        
        if (event.shiftKey) {
          // Ctrl+Shift+Z or Cmd+Shift+Z for redo
          if (canRedo) {
            redo();
          }
        } else {
          // Ctrl+Z or Cmd+Z for undo
          if (canUndo) {
            undo();
          }
        }
      } else if (isCtrlOrCmd && event.key === 'y') {
        // Ctrl+Y for redo (Windows standard)
        event.preventDefault();
        if (canRedo) {
          redo();
        }
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    
    return () => {
      document.removeEventListener('keydown', handleKeyDown);
    };
  }, [canUndo, canRedo, undo, redo]);

  return {
    canUndo,
    canRedo,
    undo,
    redo,
    store,
    clear,
  };
}
