<template>
  <div class="dropdown">
    <button
      aria-haspopup="true"
      :aria-label="dropdown.label"
      :aria-expanded="visible"
      id="dropdownBtn"
      class="dropdown__button"
      ref="toggle"
      @click.stop.prevent="setSelected(filtered[selector].value)"
      @keydown.enter.stop.prevent="setSelected(filtered[selector].value)"
    >
      {{ selected }}
      <arrow-icon class="dropdown__arrow" :class="{ 'dropdown__arrow--open': visible }"></arrow-icon>
    </button>
    <form @submit.stop.prevent="" @keydown.esc.stop.prevent="setSelected(filtered[selector].value)" ref="searchbox" class="search" :class="{ 'search--hidden': !visible }">
      <label for="search" class="search__box">
        <span class="search__label" id="searchLabel" v-text="dropdown.search.label"></span>
        <input
          type="search"
          name="search"
          id="search"
          ref="search"
          autocomplete="off"
          class="search__input"
          aria-describedby="searchLabel"
          aria-owns="results"
          :placeholder="dropdown.search.placeholder"
          :aria-expanded="visible"
          aria-autocomplete="both"
          :aria-activedescendant="descendant"
          v-model="search"
          @keydown.down.stop.prevent="$refs.listbox.focus()"
        >
        <button type="submit" class="search__control">
          <search-icon class="search__icon"></search-icon>
        </button>
      </label>
      <ul
        tabindex="-1"
        role="listbox"
        aria-labelledby="dropdownBtn"
        :aria-activedescendant="descendant"
        id="results"
        class="search__listbox"
        ref="listbox"
        @keydown.down.stop.prevent="down"
        @keydown.up.stop.prevent="up"
        @keydown.esc.stop.prevent="setSelected(filtered[selector].value)"
        @keydown.enter.stop.prevent="setSelected(filtered[selector].value)"
      >
        <li
          v-for="(option, index) in filtered"
          :key="`${option.value}_${index}`"
          :id="`${option.value}__${index}`"
          class="search__listitem"
          :aria-selected="`${option.value}__${index}` === descendant"
          v-text="option.label"
          ref="option"
          role="option"
          @click.stop.prevent="setSelected(option.value, index)"
        >
        </li>
      </ul>
    </form>
  </div>
</template>

<script>
export default {
  name: 'dropdown-search',
  components: {
    ArrowIcon: () => import('@/components/icons/ArrowIcon.vue'),
    SearchIcon: () => import('@/components/icons/SearchIcon.vue'),
  },
  props: {
    dropdown: {
      type: Object,
      required: true,
      validator: (val) => {
        const KEYS = ['label', 'search', 'options'];
        return KEYS.every(key => val.hasOwnProperty(key));
      }
    },
    value: {
      required: true,
    }
  },
  data() {
    return {
      visible: false,
      selector: 0,
      scroll: 50,
      search: '',
    }
  },
  watch: {
    search() {
      this.selector = 0;
    }
  },
  computed: {
    filtered() {
      return this.search ? this.dropdown.options.filter((option) => option.value.indexOf(this.search.toLowerCase()) !== -1) : this.dropdown.options;
    },
    selected() {
      return (this.value && this.filtered) ? this.filtered[this.selector].label : this.dropdown.label;
    },
    descendant() {
      return (this.value && this.filtered) ? `${this.filtered[this.selector].value}__${this.selector}` : '';
    },
  },
  methods: {
    up() {
      if (this.selector === 0) {
        this.selector = this.filtered.length - 1;
        this.$refs.searchbox.scrollTop = (this.filtered.length - 1) * this.scroll;
        this.$refs.search.focus();
      } else {
        this.selector--;
        this.$refs.searchbox.scrollTop -= this.scroll;
      }
    },
    down() {
      if (this.selector === this.filtered.length - 1) {
        this.selector = 0;
        this.$refs.searchbox.scrollTop = 0;
        this.$refs.search.focus();
      } else {
        this.selector++;
        this.$refs.searchbox.scrollTop += this.scroll;
      }
    },
    setSelected(val, index) {
      if (index || index === 0) {
        this.selector = index;
      }
      this.$emit('input', val);
      this.toggleListbox();
    },
    toggleListbox() {
      this.visible = !this.visible;
      if (this.visible) {
        this.$nextTick(() => {
          this.$refs.searchbox.scrollTop = (this.selector * this.scroll);
          this.$refs.search.focus();
        });
      } else {
        this.$refs.toggle.focus();
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.dropdown {
  position: relative;
  width: 275px;
  width: 27.5rem;
  &__button {
    position: relative;
    width: 100%;
    height: 50px;
    height: 5rem;
    background-color: $white;
    border-radius: border-radius(primary);
    padding: 0px 30px 0px 15px;
    padding: 0rem 3rem 0rem 1.5rem;
    text-align: left;
    perspective: 800px;
    @include body-small(medium);
    &:focus {
      outline: auto;
      outline-color: $color-primary;
    }
    &:before {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      content: '';
      opacity: 1;
      transition: opacity transition(fast);
      box-shadow: box-shadow(tertiary);
    }
    &:after {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      content: '';
      opacity: 0;
      transition: opacity transition(fast);
      box-shadow: box-shadow(quaternary);
    }
    &:hover {
      &:before {
        opacity: 0;
      }
      &:after {
        opacity: 1;
      }
    }
  }
  &__arrow {
    position: absolute;
    top: 50%;
    right: 15px;
    transition: all transition(fast);
    transform: translateY(-50%) rotate3d(0, 0, 1, 180deg);
    &--open {
      transform: translateY(-50%) rotate3d(0, 0, 1, 360deg);
    }
  }
  .search {
    position: absolute;
    top: 55px;
    left: 0;
    width: 100%;
    max-height: 210px;
    max-height: 21rem;
    overflow-y: scroll;
    background-color: $white;
    transition: opacity transition(fast);
    opacity: 1;
    box-shadow: box-shadow(quaternary);
    z-index: z-index(modal);
    &--hidden {
      opacity: 0;
      display: none;
    }
    &::-webkit-scrollbar {
      width: 10px;
      width: 1rem;
    }
    &::-webkit-scrollbar-thumb {
      border-radius: border-radius(secondary);
      background-color: $color-grey-septenary;
    }
    &__box {
      width: 100%;
      margin-bottom: 10px;
      margin-bottom: 1rem;
      position: relative;
    }
    &__label {
      display: none;
    }
    &__input {
      display: block;
      border: none;
      margin: 0 auto;
      width: calc(100% - 20px);
      width: calc(100% - 2rem);
      height: 50px;
      height: 5rem;
      background-color: $color-grey-octonary;
      border-radius: border-radius(primary);
      margin-top: 10px;
      margin-top: 1rem;
      text-indent: 15px;
      text-indent: 1.5rem;
      padding-right: 52px;
      padding-right: 5.2rem;
      &:focus {
        outline: auto;
        outline-color: $color-primary;
      }
      &::-webkit-input-placeholder { /* Chrome/Opera/Safari */
        @include body-small;
        opacity: .5;
      }
      &::-moz-placeholder { /* Firefox 19+ */
        @include body-small;
        opacity: .5;
      }
      &:-ms-input-placeholder { /* IE 10+ */
        @include body-small;
        opacity: .5;
      }
      &:-moz-placeholder { /* Firefox 18- */
        @include body-small;
        opacity: .5;
      }
    }
    &__control {
      position: absolute;
      top: calc(50% + 5px);
      right: 12px;
      transform: translateY(-50%);
      width: 46px;
      width: 4.6rem;
      height: 46px;
      height: 4.6rem;
      background-color: $color-grey-octonary;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    &__icon {
      fill: $color-primary;
    }
    &__listbox {
      list-style: none;
      padding-left: 0;
      margin-bottom: 0;
    }
    &__listitem {
      display: block;
      width: 100%;
      height: 50px;
      height: 5rem;
      text-align: left;
      padding: 0px 15px;
      padding: 0rem 1.5rem;
      @include body-small(medium);
      line-height: 50px;
      line-height: 5rem;
      cursor: pointer;
      transition: all transition(fast);
      &:hover, &:focus, &[aria-selected] {
        background-color: $color-primary;
        color: $white;
      }
    }
  }
}
</style>
