import { type IBlock } from './wysiwyg.types.js';

export interface IHistoryState {
  blocks: IBlock[];
  selectedBlockId: string | null;
  cursorPosition?: {
    blockId: string;
    offset: number;
  };
  timestamp: number;
}

export class WysiwygHistory {
  private history: IHistoryState[] = [];
  private currentIndex: number = -1;
  private maxHistorySize: number = 50;
  private lastSaveTime: number = 0;
  private saveDebounceMs: number = 500; // Debounce saves to avoid too many snapshots
  
  constructor() {
    // Initialize with empty state
    this.history = [];
    this.currentIndex = -1;
  }
  
  /**
   * Save current state to history
   */
  saveState(blocks: IBlock[], selectedBlockId: string | null, cursorPosition?: { blockId: string; offset: number }): void {
    const now = Date.now();
    
    // Debounce rapid changes (like typing)
    if (now - this.lastSaveTime < this.saveDebounceMs && this.currentIndex >= 0) {
      // Update the current state instead of creating a new one
      this.history[this.currentIndex] = {
        blocks: this.cloneBlocks(blocks),
        selectedBlockId,
        cursorPosition: cursorPosition ? { ...cursorPosition } : undefined,
        timestamp: now
      };
      return;
    }
    
    // Remove any states after current index (when we save after undoing)
    if (this.currentIndex < this.history.length - 1) {
      this.history = this.history.slice(0, this.currentIndex + 1);
    }
    
    // Add new state
    const newState: IHistoryState = {
      blocks: this.cloneBlocks(blocks),
      selectedBlockId,
      cursorPosition: cursorPosition ? { ...cursorPosition } : undefined,
      timestamp: now
    };
    
    this.history.push(newState);
    this.currentIndex++;
    
    // Limit history size
    if (this.history.length > this.maxHistorySize) {
      this.history.shift();
      this.currentIndex--;
    }
    
    this.lastSaveTime = now;
  }
  
  /**
   * Force save a checkpoint (useful for operations like block deletion)
   */
  saveCheckpoint(blocks: IBlock[], selectedBlockId: string | null, cursorPosition?: { blockId: string; offset: number }): void {
    this.lastSaveTime = 0; // Reset debounce
    this.saveState(blocks, selectedBlockId, cursorPosition);
  }
  
  /**
   * Undo to previous state
   */
  undo(): IHistoryState | null {
    if (!this.canUndo()) {
      return null;
    }
    
    this.currentIndex--;
    return this.cloneState(this.history[this.currentIndex]);
  }
  
  /**
   * Redo to next state
   */
  redo(): IHistoryState | null {
    if (!this.canRedo()) {
      return null;
    }
    
    this.currentIndex++;
    return this.cloneState(this.history[this.currentIndex]);
  }
  
  /**
   * Check if undo is available
   */
  canUndo(): boolean {
    return this.currentIndex > 0;
  }
  
  /**
   * Check if redo is available
   */
  canRedo(): boolean {
    return this.currentIndex < this.history.length - 1;
  }
  
  /**
   * Get current state
   */
  getCurrentState(): IHistoryState | null {
    if (this.currentIndex >= 0 && this.currentIndex < this.history.length) {
      return this.cloneState(this.history[this.currentIndex]);
    }
    return null;
  }
  
  /**
   * Clear history
   */
  clear(): void {
    this.history = [];
    this.currentIndex = -1;
    this.lastSaveTime = 0;
  }
  
  /**
   * Deep clone blocks
   */
  private cloneBlocks(blocks: IBlock[]): IBlock[] {
    return blocks.map(block => ({
      ...block,
      metadata: block.metadata ? { ...block.metadata } : undefined
    }));
  }
  
  /**
   * Clone a history state
   */
  private cloneState(state: IHistoryState): IHistoryState {
    return {
      blocks: this.cloneBlocks(state.blocks),
      selectedBlockId: state.selectedBlockId,
      cursorPosition: state.cursorPosition ? { ...state.cursorPosition } : undefined,
      timestamp: state.timestamp
    };
  }
  
  /**
   * Get history info for debugging
   */
  getHistoryInfo(): { size: number; currentIndex: number; canUndo: boolean; canRedo: boolean } {
    return {
      size: this.history.length,
      currentIndex: this.currentIndex,
      canUndo: this.canUndo(),
      canRedo: this.canRedo()
    };
  }
}