const nest = require('depnest')

exports.gives = nest('app.sync.catchKeyboardShortcut')

exports.needs = nest({
  'app.html.searchBar': 'first',
  'app.html.tabs': 'first',
  'app.sync.goTo': 'first',
})

var gPressed = false

exports.create = function (api) {
  return nest('app.sync.catchKeyboardShortcut', catchKeyboardShortcut)

  function catchKeyboardShortcut (root) {
    var tabs = api.app.html.tabs()
    var search = api.app.html.searchBar()
    var goTo = api.app.sync.goTo

    root.addEventListener('keydown', (ev) => {
      isTextFieldEvent(ev)
        ? textFieldShortcuts(ev)
        : genericShortcuts(ev, { tabs, search, goTo })
    })
  }
}

function isTextFieldEvent (ev) {
  const tag = ev.target.nodeName
  return (tag === 'INPUT' || tag === 'TEXTAREA')
}

function textFieldShortcuts (ev) {
  if (ev.keyCode === 13 && ev.ctrlKey) {
    ev.target.publish()  // expects the textField to have a publish method
  }
}

function genericShortcuts (ev, { tabs, search, goTo }) {
  // Messages
  if (ev.keyCode === 71) { // gg = scroll to top
    if (!gPressed) {
      gPressed = true
      window.setTimeout(() => {
        gPressed = false
      }, 3000)
      return
    }
    tabs.currentPage().scroll('first')
  }
  gPressed = false

  switch (ev.keyCode) {
    // Messages (cont'd)
    case 74: // j = older
      return tabs.currentPage().scroll(1)
    case 75: // k = newer
      return tabs.currentPage().scroll(-1)
    case 13: // enter = open
      return goToMessage(ev, { tabs, goTo })
    case 79: // o = open
      return goToMessage(ev, { tabs, goTo })
    case 192: // ` = toggle raw message view
      return toggleRawMessage(ev)

    // Tabs
    case 72: // h = left
      tabs.selectRelative(-1)
      return goTo(JSON.parse(tabs.currentPage().id))
    case 76: // l = right
      tabs.selectRelative(1)
      return goTo(JSON.parse(tabs.currentPage().id))
    case 88: // x = close
      if (tabs.selected) {
        var sel = tabs.selected
        tabs.remove(sel)
      }
      return

    // Search
    case 191: // / = routes search
      if (ev.shiftKey) search.activate('?', ev)
      else search.activate('/', ev)
      return
    case 50: // @ = mention search
      if (ev.shiftKey) search.activate('@', ev)
      return
    case 51: // # = channel search
      if (ev.shiftKey) search.activate('#', ev)
      return
    case 53: // % = message search
      if (ev.shiftKey) search.activate('%', ev)
  }
}

function goToMessage (ev, { tabs, goTo }) {
  const msg = ev.target
  if (!msg.classList.contains('Message')) return

  const { root, id } = msg.dataset
  if (!root) return goTo(id)

  goTo(root)
  setTimeout(() => scrollDownToMessage(id, tabs), 250)
}

function scrollDownToMessage (id, tabs) {
  tabs.currentPage().scroll('first')
  locateKey()

  function locateKey () {
    const msg = tabs.currentPage().querySelector(`[data-id='${id}']`)
    if (msg === null) return setTimeout(locateKey, 100)

    ;(msg.scrollIntoViewIfNeeded || msg.scrollIntoView).call(msg)
    msg.focus()
  }
}

function toggleRawMessage (ev) {
  const msg = ev.target
  if (!msg.classList.contains('Message')) return

  // this uses a crudely exported nav api
  msg.querySelector('.meta .toggle-raw-msg').click()
}


@@ -810,18 +810,22 @@
 ev) %7B%0A  
-if
+switch
  (ev.key
@@ -832,19 +832,49 @@
 Code
- === 13 && 
+) %7B%0A    case 13: // ctrl+enter%0A      if (
 ev.c
@@ -879,24 +879,28 @@
 .ctrlKey) %7B%0A
+    
     ev.targe
@@ -962,16 +962,87 @@
  method%0A
+      %7D%0A      return%0A    case 27: // esc%0A      return ev.target.blur()%0A
   %7D%0A%7D%0A%0Af

add shortcut: esc = blur for text fields