<template>
  <div @click="focus">
    <span>
      <slot>
        <input
          type="text"
          v-model="model"
        />
      </slot>
      <q-popover ref="popover" :anchor-click="false">
        <div class="list no-border" :class="{'item-delimiter': delimiter}" :style="computedWidth">
          <q-list-item
            v-for="(result, index) in computedResults"
            :key="result"
            :item="result"
            link
            :active="selectedIndex === index"
            @click.native="setValue(result)"
          ></q-list-item>
        </div>
      </q-popover>
    </span>
  </div>

</template>

<script>
// import Utils from '../utils'
import { width } from '../utils/dom'
// import filter from '../utils/filter'
import { normalizeToInterval } from '../utils/format'
import uid from '../utils/uid'

function prevent (e) {
  e.preventDefault()
  e.stopPropagation()
}

export default {
  props: {
    value: {
      type: String,
      required: true
    },
    id: {
      type: String,
      default: ''
    },
    minCharacters: {
      type: Number,
      default: 0
    },
    maxResults: {
      type: Number,
      default: 6
    },
    delay: {
      type: Number,
      default: 500
    },
    allowOther: {
      type: Boolean,
      default: true
    },
    staticData: Object,
    delimiter: Boolean
  },
  data () {
    return {
      searchId: '',
      results: [],
      selectedIndex: -1,
      width: 0,
      timer: null,
      avoidTrigger: false
    }
  },
  computed: {
    model: {
      get () {
        if (!this.avoidTrigger) {
          if (document.activeElement === this.inputEl) {
            this.__delayTrigger()
          }
        }
        else {
          this.avoidTrigger = false
        }
        return this.value
      },
      set (val) {
        this.$emit('input', val)
      }
    },
    computedResults () {
      if (this.maxResults && this.results.length > 0) {
        return this.results.slice(0, this.maxResults)
      }
    },
    computedWidth () {
      return {minWidth: this.width}
    },
    searching () {
      return this.searchId.length > 0
    }
  },
  methods: {
    focus () {
      this.$emit('search', this.model, results => {
        if (Array.isArray(results) && results.length > 0) {
          this.results = results
          if (this.$refs && this.$refs.popover) {
            if (this.$q.platform.is.desktop) {
              this.selectedIndex = 0
            }
            this.$refs.popover.open()
          }
          return
        }

        this.close()
      }, this.id)
    },
    trigger () {
      // this.width = Utils.dom.width(this.inputEl) + 'px'
      // const searchId = Utils.uid()
      this.width = width(this.inputEl) + 'px'
      const searchId = uid()
      this.searchId = searchId

      if (this.model.length < this.minCharacters) {
        this.searchId = ''
        this.close()
        return
      }

      if (this.staticData) {
        this.searchId = ''
        // this.results = Utils.filter(this.model, this.staticData)
        this.results = this.filter(this.model, this.staticData)
        if (this.$q.platform.is.desktop) {
          this.selectedIndex = 0
        }
        this.$refs.popover.open()
        return
      }

      this.$emit('search', this.model, results => {
        if (!results || this.searchId !== searchId) {
          return
        }

        this.searchId = ''
        if (this.results === results) {
          return
        }
        /* var i = this.arraycolumn(results, 'label').indexOf(this.model)
        if (i > 0) {
          this.model = this.arraycolumn(results, 'label')[i]
        } */
        if (Array.isArray(results) && results.length > 0) {
          this.results = results
          if (this.$refs && this.$refs.popover) {
            if (this.$q.platform.is.desktop) {
              this.selectedIndex = 0
            }
            this.$refs.popover.open()
          }
          return
        }
        if (this.allowOther === false && (Array.isArray(results) === false || results.length === 0)) {
          this.model = ''
        }

        this.close()
      }, this.id)
    },
    arraycolumn (list, column, indice) {
      var result
      if (typeof indice !== 'undefined') {
        result = {}
        for (var key in list) {
          result[list[key][indice]] = list[key][column]
        }
      }
      else {
        result = []
        for (key in list) {
          result.push(list[key][column])
        }
      }
      return result
    },
    close () {
      this.$refs.popover.close()
      this.results = []
      this.selectedIndex = -1
    },
    setValue (result) {
      this.avoidTrigger = true
      this.model = result.value
      this.$emit('selected', result)
      this.close()
    },
    move (offset) {
      // this.selectedIndex = Utils.format.normalizeToInterval(
      this.selectedIndex = normalizeToInterval(
        this.selectedIndex + offset,
        0,
        this.computedResults.length - 1
      )
    },
    setCurrentSelection () {
      if (this.selectedIndex >= 0) {
        this.setValue(this.results[this.selectedIndex])
      }
    },
    __delayTrigger () {
      clearTimeout(this.timer)
      this.timer = setTimeout(this.trigger, this.staticData ? 0 : this.delay)
    },
    __handleKeypress (e) {
      switch (e.keyCode || e.which) {
        case 38: // up
          this.__moveCursor(-1, e)
          break
        case 40: // down
          this.__moveCursor(1, e)
          break
        case 13: // enter
          this.setCurrentSelection()
          prevent(e)
          break
        default:
          this.close()
      }
    },
    __moveCursor (offset, e) {
      prevent(e)

      if (!this.$refs.popover.opened) {
        this.trigger()
      }
      else {
        this.move(offset)
      }
    }
  },
  mounted () {
    this.$nextTick(() => {
      this.inputEl = this.$el.querySelector('input')
      if (!this.inputEl) {
        console.error('Autocomplete needs to contain one input field in its slot.')
        return
      }
      this.inputEl.addEventListener('keydown', this.__handleKeypress)
    })
  },
  beforeDestroy () {
    clearTimeout(this.timer)
    this.inputEl.removeEventListener('keydown', this.__handleKeypress)
    this.close()
  }
}
</script>
