/**
 * @license
 * Copyright 2021 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

/** Enum for all special shortcuts */
import {ComboKey, Key, Modifier, Binding} from '../../utils/dom-util';

export enum SPECIAL_SHORTCUT {
  DOC_ONLY = 'DOC_ONLY',
  GO_KEY = 'GO_KEY',
  V_KEY = 'V_KEY',
}

/**
 * Enum for all shortcut sections, where that shortcut should be applied to.
 */
export enum ShortcutSection {
  ACTIONS = 'Actions',
  DIFFS = 'Diffs',
  EVERYWHERE = 'Global Shortcuts',
  FILE_LIST = 'File list',
  NAVIGATION = 'Navigation',
  REPLY_DIALOG = 'Reply dialog',
}

/**
 * Enum for all possible shortcut names.
 */
export enum Shortcut {
  OPEN_SHORTCUT_HELP_DIALOG = 'OPEN_SHORTCUT_HELP_DIALOG',
  GO_TO_USER_DASHBOARD = 'GO_TO_USER_DASHBOARD',
  GO_TO_OPENED_CHANGES = 'GO_TO_OPENED_CHANGES',
  GO_TO_MERGED_CHANGES = 'GO_TO_MERGED_CHANGES',
  GO_TO_ABANDONED_CHANGES = 'GO_TO_ABANDONED_CHANGES',
  GO_TO_WATCHED_CHANGES = 'GO_TO_WATCHED_CHANGES',

  CURSOR_NEXT_CHANGE = 'CURSOR_NEXT_CHANGE',
  CURSOR_PREV_CHANGE = 'CURSOR_PREV_CHANGE',
  OPEN_CHANGE = 'OPEN_CHANGE',
  NEXT_PAGE = 'NEXT_PAGE',
  PREV_PAGE = 'PREV_PAGE',
  TOGGLE_CHANGE_STAR = 'TOGGLE_CHANGE_STAR',
  REFRESH_CHANGE_LIST = 'REFRESH_CHANGE_LIST',
  OPEN_SUBMIT_DIALOG = 'OPEN_SUBMIT_DIALOG',
  TOGGLE_ATTENTION_SET = 'TOGGLE_ATTENTION_SET',

  OPEN_REPLY_DIALOG = 'OPEN_REPLY_DIALOG',
  OPEN_DOWNLOAD_DIALOG = 'OPEN_DOWNLOAD_DIALOG',
  OPEN_COPY_LINKS_DROPDOWN = 'OPEN_COPY_LINKS_DROPDOWN',
  EXPAND_ALL_MESSAGES = 'EXPAND_ALL_MESSAGES',
  COLLAPSE_ALL_MESSAGES = 'COLLAPSE_ALL_MESSAGES',
  UP_TO_DASHBOARD = 'UP_TO_DASHBOARD',
  UP_TO_CHANGE = 'UP_TO_CHANGE',
  TOGGLE_DIFF_MODE = 'TOGGLE_DIFF_MODE',
  REFRESH_CHANGE = 'REFRESH_CHANGE',
  EDIT_TOPIC = 'EDIT_TOPIC',
  DIFF_AGAINST_BASE = 'DIFF_AGAINST_BASE',
  DIFF_AGAINST_LATEST = 'DIFF_AGAINST_LATEST',
  DIFF_BASE_AGAINST_LEFT = 'DIFF_BASE_AGAINST_LEFT',
  DIFF_RIGHT_AGAINST_LATEST = 'DIFF_RIGHT_AGAINST_LATEST',
  DIFF_BASE_AGAINST_LATEST = 'DIFF_BASE_AGAINST_LATEST',

  NEXT_LINE = 'NEXT_LINE',
  PREV_LINE = 'PREV_LINE',
  VISIBLE_LINE = 'VISIBLE_LINE',
  NEXT_CHUNK = 'NEXT_CHUNK',
  PREV_CHUNK = 'PREV_CHUNK',
  TOGGLE_ALL_DIFF_CONTEXT = 'TOGGLE_ALL_DIFF_CONTEXT',
  NEXT_COMMENT_THREAD = 'NEXT_COMMENT_THREAD',
  PREV_COMMENT_THREAD = 'PREV_COMMENT_THREAD',
  EXPAND_ALL_COMMENT_THREADS = 'EXPAND_ALL_COMMENT_THREADS',
  COLLAPSE_ALL_COMMENT_THREADS = 'COLLAPSE_ALL_COMMENT_THREADS',
  LEFT_PANE = 'LEFT_PANE',
  RIGHT_PANE = 'RIGHT_PANE',
  TOGGLE_LEFT_PANE = 'TOGGLE_LEFT_PANE',
  NEW_COMMENT = 'NEW_COMMENT',
  SAVE_COMMENT = 'SAVE_COMMENT',
  OPEN_DIFF_PREFS = 'OPEN_DIFF_PREFS',
  TOGGLE_DIFF_REVIEWED = 'TOGGLE_DIFF_REVIEWED',

  NEXT_FILE = 'NEXT_FILE',
  PREV_FILE = 'PREV_FILE',
  NEXT_FILE_WITH_COMMENTS = 'NEXT_FILE_WITH_COMMENTS',
  PREV_FILE_WITH_COMMENTS = 'PREV_FILE_WITH_COMMENTS',
  NEXT_UNREVIEWED_FILE = 'NEXT_UNREVIEWED_FILE',
  CURSOR_NEXT_FILE = 'CURSOR_NEXT_FILE',
  CURSOR_PREV_FILE = 'CURSOR_PREV_FILE',
  OPEN_FILE = 'OPEN_FILE',
  TOGGLE_FILE_REVIEWED = 'TOGGLE_FILE_REVIEWED',
  TOGGLE_ALL_INLINE_DIFFS = 'TOGGLE_ALL_INLINE_DIFFS',
  TOGGLE_INLINE_DIFF = 'TOGGLE_INLINE_DIFF',
  TOGGLE_HIDE_ALL_COMMENT_THREADS = 'TOGGLE_HIDE_ALL_COMMENT_THREADS',
  OPEN_FILE_LIST = 'OPEN_FILE_LIST',

  OPEN_FIRST_FILE = 'OPEN_FIRST_FILE',
  OPEN_LAST_FILE = 'OPEN_LAST_FILE',

  SEARCH = 'SEARCH',
  EMOJI_DROPDOWN = 'EMOJI_DROPDOWN',
  MENTIONS_DROPDOWN = 'MENTIONS_DROPDOWN',
  TOGGLE_BLAME = 'TOGGLE_BLAME',

  TOGGLE_CHECKBOX = 'TOGGLE_CHECKBOX',
}

export interface ShortcutHelpItem {
  shortcut: Shortcut;
  text: string;
  bindings: Binding[];
}

export function createShortcutConfig() {
  const config = new Map<ShortcutSection, ShortcutHelpItem[]>();
  function describe(
    shortcut: Shortcut,
    section: ShortcutSection,
    text: string,
    binding: Binding,
    ...moreBindings: Binding[]
  ) {
    if (!config.has(section)) {
      config.set(section, []);
    }
    const shortcuts = config.get(section);
    if (shortcuts) {
      shortcuts.push({shortcut, text, bindings: [binding, ...moreBindings]});
    }
  }

  describe(Shortcut.SEARCH, ShortcutSection.EVERYWHERE, 'Search', {key: '/'});
  describe(
    Shortcut.OPEN_SHORTCUT_HELP_DIALOG,
    ShortcutSection.EVERYWHERE,
    'Show this dialog',
    {key: '?'}
  );
  describe(
    Shortcut.GO_TO_USER_DASHBOARD,
    ShortcutSection.EVERYWHERE,
    'Go to User Dashboard',
    {key: 'i', combo: ComboKey.G}
  );
  describe(
    Shortcut.GO_TO_OPENED_CHANGES,
    ShortcutSection.EVERYWHERE,
    'Go to Opened Changes',
    {key: 'o', combo: ComboKey.G}
  );
  describe(
    Shortcut.GO_TO_MERGED_CHANGES,
    ShortcutSection.EVERYWHERE,
    'Go to Merged Changes',
    {key: 'm', combo: ComboKey.G}
  );
  describe(
    Shortcut.GO_TO_ABANDONED_CHANGES,
    ShortcutSection.EVERYWHERE,
    'Go to Abandoned Changes',
    {key: 'a', combo: ComboKey.G}
  );
  describe(
    Shortcut.GO_TO_WATCHED_CHANGES,
    ShortcutSection.EVERYWHERE,
    'Go to Watched Changes',
    {key: 'w', combo: ComboKey.G}
  );
  describe(
    Shortcut.TOGGLE_CHECKBOX,
    ShortcutSection.ACTIONS,
    'Toggle checkbox',
    {key: 'x'}
  );
  describe(
    Shortcut.CURSOR_NEXT_CHANGE,
    ShortcutSection.ACTIONS,
    'Select next change',
    {key: 'j', allowRepeat: true}
  );
  describe(
    Shortcut.CURSOR_PREV_CHANGE,
    ShortcutSection.ACTIONS,
    'Select previous change',
    {key: 'k', allowRepeat: true}
  );
  describe(
    Shortcut.OPEN_CHANGE,
    ShortcutSection.ACTIONS,
    'Show selected change',
    {key: 'o'}
  );
  describe(
    Shortcut.NEXT_PAGE,
    ShortcutSection.ACTIONS,
    'Go to next page',
    {key: 'n'},
    {key: ']'}
  );
  describe(
    Shortcut.PREV_PAGE,
    ShortcutSection.ACTIONS,
    'Go to previous page',
    {key: 'p'},
    {key: '['}
  );
  describe(
    Shortcut.OPEN_REPLY_DIALOG,
    ShortcutSection.ACTIONS,
    'Open reply dialog to publish comments and add reviewers',
    {key: 'a'}
  );
  describe(
    Shortcut.OPEN_DOWNLOAD_DIALOG,
    ShortcutSection.ACTIONS,
    'Open download overlay',
    {key: 'd'}
  );
  describe(
    Shortcut.OPEN_COPY_LINKS_DROPDOWN,
    ShortcutSection.ACTIONS,
    'Open link dialog',
    {key: 'l'}
  );
  describe(
    Shortcut.EXPAND_ALL_MESSAGES,
    ShortcutSection.ACTIONS,
    'Expand all messages',
    {key: 'x'}
  );
  describe(
    Shortcut.COLLAPSE_ALL_MESSAGES,
    ShortcutSection.ACTIONS,
    'Collapse all messages',
    {key: 'z'}
  );
  describe(
    Shortcut.REFRESH_CHANGE,
    ShortcutSection.ACTIONS,
    'Reload the change at the latest patch',
    {key: 'R'}
  );
  describe(
    Shortcut.TOGGLE_FILE_REVIEWED,
    ShortcutSection.ACTIONS,
    'Toggle review flag on selected file',
    {key: 'r'}
  );
  describe(
    Shortcut.REFRESH_CHANGE_LIST,
    ShortcutSection.ACTIONS,
    'Refresh list of changes',
    {key: 'R'}
  );
  describe(
    Shortcut.TOGGLE_CHANGE_STAR,
    ShortcutSection.ACTIONS,
    'Star/unstar change',
    {key: 's'}
  );
  describe(
    Shortcut.OPEN_SUBMIT_DIALOG,
    ShortcutSection.ACTIONS,
    'Open submit dialog',
    {key: 'S'}
  );
  describe(
    Shortcut.TOGGLE_ATTENTION_SET,
    ShortcutSection.ACTIONS,
    'Toggle attention set status',
    {key: 'T'}
  );
  describe(Shortcut.EDIT_TOPIC, ShortcutSection.ACTIONS, 'Add a change topic', {
    key: 't',
  });
  describe(
    Shortcut.DIFF_AGAINST_BASE,
    ShortcutSection.DIFFS,
    'Diff against base',
    {key: Key.DOWN, combo: ComboKey.V},
    {key: 's', combo: ComboKey.V}
  );
  describe(
    Shortcut.DIFF_AGAINST_LATEST,
    ShortcutSection.DIFFS,
    'Diff against latest patchset',
    {key: Key.UP, combo: ComboKey.V},
    {key: 'w', combo: ComboKey.V}
  );
  describe(
    Shortcut.DIFF_BASE_AGAINST_LEFT,
    ShortcutSection.DIFFS,
    'Diff base against left',
    {key: Key.LEFT, combo: ComboKey.V},
    {key: 'a', combo: ComboKey.V}
  );
  describe(
    Shortcut.DIFF_RIGHT_AGAINST_LATEST,
    ShortcutSection.DIFFS,
    'Diff right against latest',
    {key: Key.RIGHT, combo: ComboKey.V},
    {key: 'd', combo: ComboKey.V}
  );
  describe(
    Shortcut.DIFF_BASE_AGAINST_LATEST,
    ShortcutSection.DIFFS,
    'Diff base against latest',
    {key: 'b', combo: ComboKey.V}
  );

  describe(
    Shortcut.NEXT_LINE,
    ShortcutSection.DIFFS,
    'Go to next line',
    {key: 'j', allowRepeat: true},
    {key: Key.DOWN, allowRepeat: true}
  );
  describe(
    Shortcut.PREV_LINE,
    ShortcutSection.DIFFS,
    'Go to previous line',
    {key: 'k', allowRepeat: true},
    {key: Key.UP, allowRepeat: true}
  );
  describe(
    Shortcut.VISIBLE_LINE,
    ShortcutSection.DIFFS,
    'Move cursor to currently visible code',
    {key: '.'}
  );
  describe(
    Shortcut.NEXT_CHUNK,
    ShortcutSection.DIFFS,
    'Go to next diff chunk',
    {
      key: 'n',
    }
  );
  describe(
    Shortcut.PREV_CHUNK,
    ShortcutSection.DIFFS,
    'Go to previous diff chunk',
    {key: 'p'}
  );
  describe(
    Shortcut.TOGGLE_ALL_DIFF_CONTEXT,
    ShortcutSection.DIFFS,
    'Toggle all diff context',
    {key: 'X'}
  );
  describe(
    Shortcut.NEXT_COMMENT_THREAD,
    ShortcutSection.DIFFS,
    'Go to next comment thread',
    {key: 'N'}
  );
  describe(
    Shortcut.PREV_COMMENT_THREAD,
    ShortcutSection.DIFFS,
    'Go to previous comment thread',
    {key: 'P'}
  );
  describe(
    Shortcut.EXPAND_ALL_COMMENT_THREADS,
    ShortcutSection.DIFFS,
    'Expand all comment threads',
    {key: 'e', docOnly: true}
  );
  describe(
    Shortcut.COLLAPSE_ALL_COMMENT_THREADS,
    ShortcutSection.DIFFS,
    'Collapse all comment threads',
    {key: 'E', docOnly: true}
  );
  describe(
    Shortcut.TOGGLE_HIDE_ALL_COMMENT_THREADS,
    ShortcutSection.DIFFS,
    'Hide/Display all comment threads',
    {key: 'h'}
  );
  describe(Shortcut.LEFT_PANE, ShortcutSection.DIFFS, 'Select left pane', {
    key: Key.LEFT,
    modifiers: [Modifier.SHIFT_KEY],
  });
  describe(Shortcut.RIGHT_PANE, ShortcutSection.DIFFS, 'Select right pane', {
    key: Key.RIGHT,
    modifiers: [Modifier.SHIFT_KEY],
  });
  describe(
    Shortcut.TOGGLE_LEFT_PANE,
    ShortcutSection.DIFFS,
    'Hide/show left diff',
    {key: 'A'}
  );
  describe(Shortcut.NEW_COMMENT, ShortcutSection.DIFFS, 'Draft new comment', {
    key: 'c',
  });
  describe(
    Shortcut.SAVE_COMMENT,
    ShortcutSection.DIFFS,
    'Save comment',
    {key: Key.ENTER, modifiers: [Modifier.CTRL_KEY]},
    {key: Key.ENTER, modifiers: [Modifier.META_KEY]},
    {key: 's', modifiers: [Modifier.CTRL_KEY]},
    {key: 's', modifiers: [Modifier.META_KEY]}
  );
  describe(
    Shortcut.OPEN_DIFF_PREFS,
    ShortcutSection.DIFFS,
    'Show diff preferences',
    {key: ','}
  );
  describe(
    Shortcut.TOGGLE_DIFF_REVIEWED,
    ShortcutSection.DIFFS,
    'Mark/unmark file as reviewed',
    {key: 'r'}
  );
  describe(
    Shortcut.TOGGLE_DIFF_MODE,
    ShortcutSection.DIFFS,
    'Toggle unified/side-by-side diff',
    {key: 'm'}
  );
  describe(
    Shortcut.NEXT_UNREVIEWED_FILE,
    ShortcutSection.DIFFS,
    'Mark file as reviewed and go to next unreviewed file',
    {key: 'M'}
  );
  describe(Shortcut.TOGGLE_BLAME, ShortcutSection.DIFFS, 'Toggle blame', {
    key: 'b',
  });
  describe(Shortcut.OPEN_FILE_LIST, ShortcutSection.DIFFS, 'Open file list', {
    key: 'f',
  });
  describe(Shortcut.NEXT_FILE, ShortcutSection.NAVIGATION, 'Go to next file', {
    key: ']',
  });
  describe(
    Shortcut.PREV_FILE,
    ShortcutSection.NAVIGATION,
    'Go to previous file',
    {key: '['}
  );
  describe(
    Shortcut.NEXT_FILE_WITH_COMMENTS,
    ShortcutSection.NAVIGATION,
    'Go to next file that has comments',
    {key: 'J'}
  );
  describe(
    Shortcut.PREV_FILE_WITH_COMMENTS,
    ShortcutSection.NAVIGATION,
    'Go to previous file that has comments',
    {key: 'K'}
  );
  describe(
    Shortcut.OPEN_FIRST_FILE,
    ShortcutSection.NAVIGATION,
    'Go to first file',
    {key: ']'}
  );
  describe(
    Shortcut.OPEN_LAST_FILE,
    ShortcutSection.NAVIGATION,
    'Go to last file',
    {key: '['}
  );
  describe(
    Shortcut.UP_TO_DASHBOARD,
    ShortcutSection.NAVIGATION,
    'Up to dashboard',
    {key: 'u'}
  );
  describe(Shortcut.UP_TO_CHANGE, ShortcutSection.NAVIGATION, 'Up to change', {
    key: 'u',
  });

  describe(
    Shortcut.CURSOR_NEXT_FILE,
    ShortcutSection.FILE_LIST,
    'Select next file',
    {key: 'j', allowRepeat: true},
    {key: Key.DOWN, allowRepeat: true}
  );
  describe(
    Shortcut.CURSOR_PREV_FILE,
    ShortcutSection.FILE_LIST,
    'Select previous file',
    {key: 'k', allowRepeat: true},
    {key: Key.UP, allowRepeat: true}
  );
  describe(
    Shortcut.OPEN_FILE,
    ShortcutSection.FILE_LIST,
    'Go to selected file',
    {key: 'o'},
    {key: Key.ENTER}
  );
  describe(
    Shortcut.TOGGLE_ALL_INLINE_DIFFS,
    ShortcutSection.FILE_LIST,
    'Show/hide all inline diffs',
    {key: 'I'}
  );
  describe(
    Shortcut.TOGGLE_INLINE_DIFF,
    ShortcutSection.FILE_LIST,
    'Show/hide selected inline diff',
    {key: 'i'}
  );
  describe(
    Shortcut.EMOJI_DROPDOWN,
    ShortcutSection.REPLY_DIALOG,
    'Emoji dropdown',
    {key: ':', docOnly: true}
  );
  describe(
    Shortcut.MENTIONS_DROPDOWN,
    ShortcutSection.REPLY_DIALOG,
    'Mentions dropdown',
    {key: '@', docOnly: true}
  );
  return config;
}
