const m = require('mithril')
const util = require('./util')

let activeBox = null
let boxIndex = 1

document.body.addEventListener('click', function() {
  activeBox = null
  m.redraw()
})

const Combobox = {
  oninit: function(vnode) {
    this.filtered = []
    this.open = false
    this.input = null
    this.id = boxIndex++
    this.onbeforeupdate(vnode)
    this.focus = this.onFocus.bind(this, vnode)
  },

  onbeforeupdate: function(vnode) {
    if (!vnode.attrs.value) {
      this.filtered = vnode.attrs.items || []
      return
    }

    let val = vnode.attrs.value.toLocaleLowerCase()
    this.filtered = vnode.attrs.items.filter(item => {
      return item.toLocaleLowerCase().indexOf(val) >= 0
    })
  },

  onInput: function(vnode, e) {
    this.smartOpen(vnode)
    if (vnode.attrs.oninput) {
      vnode.attrs.oninput(e)
    }
  },

  onDone: function(vnode) {
    if (vnode.attrs.ondone) {
      vnode.attrs.ondone()
    }
  },

  onFocus: function(vnode) {
    this.input.focus()
  },

  selectText: function(vnode, text) {
    this.input.value = text
    this.onInput(vnode, { target: this.input })
    activeBox = null
    this.onDone(vnode)
    return false
  },

  onKeyPress: function(vnode, e) {
    if (e.key === 'ArrowDown') {
      if (e.target.dataset.type === 'input' && e.target.nextElementSibling && e.target.nextElementSibling.childNodes) {
        e.target.nextElementSibling.childNodes[0].focus()
      } else if (e.target.dataset.type === 'item') {
        if (e.target.nextElementSibling) {
          e.target.nextElementSibling.focus()
        } else {
          this.input.focus()
        }
      }
      return false
    }
    if (e.key === 'ArrowUp') {
      if (e.target.dataset.type === 'input' && e.target.nextElementSibling && e.target.nextElementSibling.lastChild) {
        e.target.nextElementSibling.scrollTop = e.target.nextElementSibling.scrollHeight
        e.target.nextElementSibling.lastChild.focus()
      } else if (e.target.dataset.type === 'item') {
        if (e.target.previousElementSibling) {
          e.target.previousElementSibling.focus()
        } else {
          this.input.focus()
        }
      }
      return false
    }
    if (e.key === 'Enter') {
      let newVal = ''
      if (e.target.dataset.type === 'input' && this.filtered.length) {
        if (e.target.value && e.target.value !== this.filtered[0]) {
          return this.selectText(vnode, this.filtered[0])
        }
        this.onDone(vnode)
        return false
      }
      if (e.target.dataset.type === 'item') {
        return this.selectText(vnode, e.target.dataset.value)
      }
    }
  },

  smartOpen: function(vnode) {
    if (this.input.value && this.input.value === this.filtered[0]) {
      activeBox = null
    } else {
      activeBox = this.id
    }
    m.redraw()
  },

  view: function(vnode) {
    closeBox = false

    return m('div.form-item.combobox', {
      class: vnode.attrs.class,
      onclick: util.cancelPropagation,
    }, [
      m('label', vnode.attrs.label),
      m('input', {
        'data-type': 'input',
        oncreate: (e) => { this.input = e.dom },
        onkeydown: (e) => this.onKeyPress(vnode, e),
        type: vnode.attrs.type || 'text',
        value: vnode.attrs.value,
        onfocus: () => this.smartOpen(vnode),
        placeholder: vnode.attrs.placeholder || '',
        oninput: this.onInput.bind(this, vnode),
      }),
      activeBox === this.id
        ? m('div.combobox-list', [
            this.filtered.slice(0, 50).map(item => {
              return m('div.combobox-list-item', {
                'data-type': 'item',
                'data-value': item,
                onkeydown: (e) => this.onKeyPress(vnode, e),
                onclick: (e) => this.selectText(vnode, item),
                tabindex: '0',
              }, item)
            })
          ])
        : null,
    ])
  }
}

module.exports = Combobox