const level = {
  debug: 'debug',
  info: 'info',
  error: 'error'
};

export const Logger = {
  messages: [],
  consoleOutput: true,
  info(module, procedure, message) {
    this._append(level.info, module, procedure, message);
  },
  debug(module, procedure, message) {
    this._append(level.debug, module, procedure, message);
  },
  error(module, procedure, message) {
    this._append(level.error, module, procedure, message);
  },
  _append(level, module, procedure, message) {
    const log = {
      level,
      module,
      procedure,
      message: message,
      time: new Date().getTime()
    };
    this.messages.push(log);
    if (this.consoleOutput) this._print(log);
    if (this.messages.length > 15000) this.messages.shift();
  },
  _print(log) {
    let time = new Date(log.time);
    console.info(`[${log.level === 'error' ? 'x' : '*'}][${time.toLocaleString()}](${log.module} - ${log.procedure}) ${log.message}`);
  },
  filter(module, procedure) {
    return this.messages.filter((i) => i.module === module && i.procedure === procedure);
  },
  enableConsoleOutput() {
    this.consoleOutput = true;
  },
  disableConsoleOutput() {
    this.consoleOutput = false;
  },
  peek(rows) {
    return this.messages.slice(-rows);
  },
  search(module, procedure, keyword) {
    return this.messages.filter((i) => {
      let r = i.module === module;
      if (!r) return false;
      if (procedure) {
        if (i.procedure !== procedure) return false;
      }
      if (keyword) {
        if (i.message.indexOf(keyword) === -1) return false;
      }
      return true;
    });
  }
};

export const formatTime = (date) => {
  let str =
    date.getFullYear() +
    '-0' +
    (date.getMonth() + 1) +
    '-0' +
    date.getDate() +
    '-0' +
    date.getHours() +
    '-0' +
    date.getMinutes() +
    '-0' +
    date.getSeconds();
  str = str.replace(/(\d{4})\-0*(\d{2})\-0*(\d{2})\-0*(\d{2})\-0*(\d{2})\-0*(\d{2})/gi, '$1$2$3$4$5$6');
  return str;
};

export function sliceTime(input) {
  return input.match(/.{1,2}/g).map(Number);
}

const keyMap = {
  CUSTOM_1: 0x01,
  A: 0x04,
  B: 0x05,
  C: 0x06,
  D: 0x07,
  E: 0x08,
  F: 0x09,
  G: 0x0a,
  H: 0x0b,
  I: 0x0c,
  J: 0x0d,
  K: 0x0e,
  L: 0x0f,
  M: 0x10,
  N: 0x11,
  O: 0x12,
  P: 0x13,
  Q: 0x14,
  R: 0x15,
  S: 0x16,
  T: 0x17,
  U: 0x18,
  V: 0x19,
  W: 0x1a,
  X: 0x1b,
  Y: 0x1c,
  Z: 0x1b,
  ENTER: 0x28,
  ESCAPE: 0x29,
  SPACE: 0x2c
};

const HotKeyBuilder = {
  control: false,
  shift: false,
  alt: false,
  guiKey: false,
  keys: [],
  withControl: () => {
    HotKeyBuilder.control = true;
    return HotKeyBuilder;
  },
  withShift: () => {
    HotKeyBuilder.shift = true;
    return HotKeyBuilder;
  },
  withAlt: () => {
    HotKeyBuilder.alt = true;
    return HotKeyBuilder;
  },
  withGuiKey: () => {
    HotKeyBuilder.guiKey = true;
    return HotKeyBuilder;
  },
  withKey: (key) => {
    if (HotKeyBuilder.keys.length >= 2) throw new Error('exceed max key bindings');
    HotKeyBuilder.keys.push(HotKeyBuilder.__mapping(key));
    return HotKeyBuilder;
  },
  __mapping: (key) => {
    return keyMap[key];
  },
  build: (REG_8 = 0x03, REG_9 = 0x00) => {
    let key1 = REG_9;
    if (HotKeyBuilder.control) key1 |= 0x01 << 0;
    if (HotKeyBuilder.shift) key1 |= 0x01 << 1;
    if (HotKeyBuilder.alt) key1 |= 0x01 << 2;
    if (HotKeyBuilder.guiKey) key1 |= 0x01 << 3;
    let codes = [
      REG_8,
      key1,
      HotKeyBuilder.keys.length ? HotKeyBuilder.keys[0] : 0x00,
      HotKeyBuilder.keys.length > 1 ? HotKeyBuilder.keys[1] : 0x00,
      0x00,
      0x00,
      0x00,
      0x00
    ];
    HotKeyBuilder.control = false;
    HotKeyBuilder.shift = false;
    HotKeyBuilder.alt = false;
    HotKeyBuilder.guiKey = false;
    HotKeyBuilder.keys = [];
    return codes;
  }
};

const enterKeyCode = (answer = 0, hangup = 0, reject = 0, micMute = 0) => {
  let code = 0;
  if (answer) code |= 0x01 << 0;
  if (hangup) code |= 0x01 << 1;
  if (reject) code |= 0x01 << 2;
  if (micMute) code |= 0x01 << 3;
  return [0x00, code];
};

const emptyCodes = [0, 0, 0, 0, 0, 0, 0, 0];

export const shortcutKeys = {
  zoom: {
    Windows: [
      ...enterKeyCode(0, 1),
      ...HotKeyBuilder.build(0x04, 0x01),
      ...HotKeyBuilder.withAlt().withKey('Q').build(),
      ...HotKeyBuilder.build(0x04, 0x10),
      ...emptyCodes
    ],
    Mac: [
      ...enterKeyCode(0, 1),
      ...HotKeyBuilder.build(0x04, 0x01),
      ...HotKeyBuilder.withGuiKey().withKey('W').build(),
      ...HotKeyBuilder.build(0x04, 0x10),
      ...emptyCodes
    ],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  teams: {
    Windows: [
      ...enterKeyCode(),
      ...HotKeyBuilder.withControl().withShift().withKey('A').build(),
      ...HotKeyBuilder.withControl().withShift().withKey('H').build(),
      ...HotKeyBuilder.withControl().withShift().withKey('D').build(),
      ...HotKeyBuilder.withControl().withShift().withKey('M').build()
    ],
    Mac: [
      ...enterKeyCode(),
      ...HotKeyBuilder.withGuiKey().withShift().withKey('A').build(),
      ...HotKeyBuilder.withGuiKey().withShift().withKey('H').build(),
      ...HotKeyBuilder.withGuiKey().withShift().withKey('D').build(),
      ...HotKeyBuilder.withGuiKey().withShift().withKey('M').build()
    ],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  'google-meeting': {
    Windows: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...HotKeyBuilder.withControl().withKey('D').build()],
    Mac: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...HotKeyBuilder.withGuiKey().withKey('D').build()],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  webex: {
    Windows: [
      ...enterKeyCode(),
      ...HotKeyBuilder.withControl().withShift().withKey('C').build(),
      ...HotKeyBuilder.withControl().withKey('L').build(),
      ...HotKeyBuilder.withControl().withKey('D').build(),
      ...HotKeyBuilder.withControl().withKey('M').build()
    ],
    Mac: [
      ...enterKeyCode(),
      ...HotKeyBuilder.withControl().withShift().withKey('C').build(),
      ...HotKeyBuilder.withGuiKey().withKey('L').build(),
      ...HotKeyBuilder.withGuiKey().withShift().withKey('D').build(),
      ...HotKeyBuilder.withGuiKey().withShift().withKey('M').build()
    ],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  feishu: {
    Windows: [
      ...enterKeyCode(),
      ...emptyCodes,
      ...emptyCodes,
      ...emptyCodes,
      ...HotKeyBuilder.withControl().withShift().withKey('D').build()
    ],
    Mac: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...HotKeyBuilder.withGuiKey().withShift().withKey('D').build()],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  lark: {
    Windows: [
      ...enterKeyCode(),
      ...emptyCodes,
      ...emptyCodes,
      ...emptyCodes,
      ...HotKeyBuilder.withControl().withShift().withKey('D').build()
    ],
    Mac: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...HotKeyBuilder.withGuiKey().withShift().withKey('D').build()],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  wechat: {
    Windows: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes],
    Mac: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  line: {
    Windows: [
      ...enterKeyCode(0, 1, 1),
      ...emptyCodes,
      ...HotKeyBuilder.withKey('ESCAPE').build(),
      ...HotKeyBuilder.withKey('ESCAPE').build(),
      ...HotKeyBuilder.withControl().withShift().withKey('A').build()
    ],
    Mac: [
      ...enterKeyCode(0, 1, 1),
      ...emptyCodes,
      ...HotKeyBuilder.withKey('ESCAPE').build(),
      ...HotKeyBuilder.withKey('ESCAPE').build(),
      ...HotKeyBuilder.withGuiKey().withShift().withKey('A').build()
    ],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  'whats-app': {
    Windows: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes],
    Mac: [
      ...enterKeyCode(),
      ...emptyCodes,
      ...HotKeyBuilder.withGuiKey().withKey('W').build(),
      ...HotKeyBuilder.withGuiKey().withKey('W').build(),
      ...HotKeyBuilder.withGuiKey().withShift().withKey('M').build()
    ],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  slack: {
    Windows: [
      ...enterKeyCode(),
      ...emptyCodes,
      ...emptyCodes,
      ...emptyCodes,
      ...HotKeyBuilder.withControl().withShift().withKey('SPACE').build()
    ],
    Mac: [
      ...enterKeyCode(),
      ...emptyCodes,
      ...emptyCodes,
      ...emptyCodes,
      ...HotKeyBuilder.withGuiKey().withShift().withKey('SPACE').build()
    ],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  },
  discord: {
    Windows: [
      ...enterKeyCode(),
      HotKeyBuilder.withControl().withKey('ENTER').build(),
      ...emptyCodes,
      ...HotKeyBuilder.withKey('ESCAPE').build(),
      ...HotKeyBuilder.withControl().withShift().withKey('M').build()
    ],
    Mac: [
      ...enterKeyCode(),
      ...HotKeyBuilder.withGuiKey().withKey('ENTER').build(),
      ...emptyCodes,
      ...HotKeyBuilder.withGuiKey().withKey('ESCAPE').build(),
      ...HotKeyBuilder.withGuiKey().withShift().withKey('M').build()
    ],
    Linux: [...enterKeyCode(), ...emptyCodes, ...emptyCodes, ...emptyCodes, ...emptyCodes]
  }
};
