import { HISTORY_MERGE_WINDOW } from './constants';

export default class History {
  constructor(service, options = {}) {
    this.service = service;
    this.undos = [];
    this.redos = [];
    this.lastCommandTime = 0;
    this.mergeWindow = options.mergeWindow || HISTORY_MERGE_WINDOW;
  }

  execute(command) {
    const now = Date.now();
    const lastCommand = this.undos[this.undos.length - 1];
    if (
      lastCommand &&
      lastCommand.updatable &&
      command.updatable &&
      typeof lastCommand.canUpdate === 'function' &&
      lastCommand.canUpdate(command, now - this.lastCommandTime, this.mergeWindow)
    ) {
      lastCommand.update(command);
      lastCommand.execute();
      this.redos = [];
      this.lastCommandTime = now;
      return {
        command: lastCommand,
        merged: true,
      };
    }

    command.execute();
    this.undos.push(command);
    this.redos = [];
    this.lastCommandTime = now;
    return {
      command,
      merged: false,
    };
  }

  undo() {
    const command = this.undos.pop();
    if (!command) return null;
    command.undo();
    this.redos.push(command);
    return command;
  }

  redo() {
    const command = this.redos.pop();
    if (!command) return null;
    command.execute();
    this.undos.push(command);
    return command;
  }

  clear() {
    this.undos = [];
    this.redos = [];
    this.lastCommandTime = 0;
  }

  canUndo() {
    return this.undos.length > 0;
  }

  canRedo() {
    return this.redos.length > 0;
  }

  getState() {
    return {
      canUndo: this.canUndo(),
      canRedo: this.canRedo(),
      undoCount: this.undos.length,
      redoCount: this.redos.length,
    };
  }
}
