import { makeAutoObservable } from 'mobx';
import View from '../app/View';
import hotkeys from 'hotkeys-js';

export interface Shortcut {
  /**
   * The shortcut combo to trigger the action.
   * @example
   * 'ctrl+s'
   * 'command+s'
   * ['ctrl+s', 'command+s']
   * 'ctrl+shift+s'
   */
  combo: string | string[];
  /**
   * The action to be called when the shortcut is triggered.
   * @returns
   */
  action: () => void;
  /**
   * The description of the shortcut. Added for convenience.
   * @optional
   * @example
   * 'Save the file to disk'
   * 'Open the preview'
   */
  description?: string;
  /**
   * The view where the shortcut should be active. It should match with your view id.
   * The shortcut will be active in all views if not specified.
   * @optional
   */
  view?: string;
}

/**
 * The Shortcuts class handles all the keyboard shortcuts in the app.
 * It uses the hotkeys library to handle the shortcuts.
 */
export class Shortcuts {
  currentView: View;
  shiftPress: boolean;
  /**
   * The scope where the shortcut should be active.
   * It should match with your scope id.
   */
  scoped: { [key: string]: { [id: string]: () => void } };

  constructor(view: View) {
    this.currentView = view;
    this.shiftPress = false;
    this.scoped = {};
    hotkeys('shift', () => {
      this.setShiftPress(true);
    });

    makeAutoObservable(this);
  }

  /**
   * Register a new shortcut
   * @param shortcut the shortcut combo to trigger the action.
   * @param callback the action to be called when the shortcut is triggered.
   */
  register = (shortcut: string | string[], callback: () => void) => {
    if (typeof shortcut === 'string') {
      hotkeys(shortcut, callback);
    } else {
      shortcut.forEach((combo) => {
        hotkeys(combo, callback);
      });
    }
  };

  /**
   * Unregister a current shortcut
   * @param shortcut the shortcut combo to be unregistered.
   */
  unregister = (shortcut: string | string[]) => {
    if (typeof shortcut === 'string') {
      hotkeys.unbind(shortcut);
    } else {
      shortcut.forEach((combo) => {
        hotkeys.unbind(combo);
      });
    }
  };

  /**
   * Register a list of shortcuts to be used in the app.
   * @param shortcuts the shortcuts to be registered.
   */
  registerAppShortcuts = (shortcuts: Shortcut[]) => {
    const applyShortcut = (shortcut: Shortcut) => {
      this.register(shortcut.combo, () => {
        if (shortcut.view && shortcut.view !== this.currentView.path) {
          return;
        }

        shortcut.action();
      });
    };
    shortcuts.forEach(applyShortcut);
  };

  /**
   * Set the shift key press state.
   * @param value boolean if true, the shift key is pressed
   */
  private setShiftPress = (value: boolean) => {
    this.shiftPress = value;
  };
}
