import {
  play,
  pause,
  stop,
  adjustVolume,
  toggleRepeat,
  toggleShuffle,
  openMediaFileDialog,
  seekForward,
  seekBackward,
  reverseList,
  nextN,
  next,
  previous,
  toggleDoubleSizeMode,
  toggleWindow
} from "./actionCreators";

import { TOGGLE_TIME_MODE, TOGGLE_LLAMA_MODE } from "./actionTypes";

import { arraysAreEqual } from "./utils";
import { Dispatch } from "./types";

const IGNORE_EVENTS_FROM_TAGS = new Set(["input", "textarea", "select"]);

export function bindHotkeys(dispatch: Dispatch): () => void {
  let keylog: number[] = [];
  const trigger = [
    78, // N
    85, // U
    76, // L
    76, // L
    83, // S
    79, // O
    70, // F
    84 // T
  ];

  const listener = (e: KeyboardEvent) => {
    if (
      e.target instanceof Element &&
      IGNORE_EVENTS_FROM_TAGS.has(e.target.tagName.toLowerCase())
    ) {
      return;
    }
    if (e.ctrlKey) {
      switch (e.keyCode) {
        case 68: // CTRL+D
          dispatch(toggleDoubleSizeMode());
          e.preventDefault(); // Supress the "Bookmark" action on windows.
          break;
        case 76: // CTRL+L FIXME
          break;
        case 82: // CTRL+R
          dispatch(reverseList());
          break;
        case 84: // CTRL+T
          dispatch({ type: TOGGLE_TIME_MODE });
          break;
      }
    } else if (e.altKey) {
      switch (e.keyCode) {
        case 87: // ALT+W
          dispatch(toggleWindow("main"));
          break;
        case 69: // ALT+E
          dispatch(toggleWindow("playlist"));
          break;
        case 71: // ALT+G
          dispatch(toggleWindow("equalizer"));
          break;
      }
    } else {
      switch (e.keyCode) {
        case 37: // left arrow
          dispatch(seekBackward(5));
          break;
        case 38: // up arrow
          dispatch(adjustVolume(1));
          break;
        case 39: // right arrow
          dispatch(seekForward(5));
          break;
        case 40: // down arrow
          dispatch(adjustVolume(-1));
          break;
        case 66: // B
          dispatch(next());
          break;
        case 67: // C
          dispatch(pause());
          break;
        case 76: // L
          dispatch(openMediaFileDialog());
          break;
        case 82: // R
          dispatch(toggleRepeat());
          break;
        case 83: // S
          dispatch(toggleShuffle());
          break;
        case 86: // V
          dispatch(stop());
          break;
        case 88: // X
          dispatch(play());
          break;
        case 90: // Z
          dispatch(previous());
          break;
        case 96: // numpad 0
          dispatch(openMediaFileDialog());
          break;
        case 97: // numpad 1
          dispatch(nextN(-10));
          break;
        case 98: // numpad 2
          dispatch(adjustVolume(-1));
          break;
        case 99: // numpad 3
          dispatch(nextN(10));
          break;
        case 100: // numpad 4
          dispatch(previous());
          break;
        case 101: // numpad 5
          dispatch(play());
          break;
        case 102: // numpad 6
          dispatch(next());
          break;
        case 103: // numpad 7
          dispatch(seekBackward(5));
          break;
        case 104: // numpad 8
          dispatch(adjustVolume(1));
          break;
        case 105: // numpad 9
          dispatch(seekForward(5));
          break;
      }
    }

    // Easter Egg

    // Ignore escape. Usually this gets swallowed by the browser, but not always.
    if (e.keyCode !== 27) {
      keylog.push(e.keyCode);
      keylog = keylog.slice(-8);
      if (arraysAreEqual(keylog, trigger)) {
        dispatch({ type: TOGGLE_LLAMA_MODE });
      }
    }
  };
  document.addEventListener("keydown", listener);

  return () => {
    document.removeEventListener("keydown", listener);
  };
}
