<template>
  <div :class="{ 'form-element' : editMode, 'modal-mode': modalMode }">
    <ui-autocomplete
      v-if="editMode"
      v-model="collectionSlugText"
      :suggestions="autocomplete"
      floating-label
      label="Collection Slug"
      :min-chars="1"
      @blur="handleSave"
      @focus="onFocus"
      @input="onInputChange"
      @select="handleSelect"
    />
    <ui-select
      v-else
      v-model="collectionSlugText"
      class="collection-slug"
      label="Collection Slug"
      floating-label
      has-search
      :loading="isLoading"
      :options="autocomplete"
      @query-change="onQueryChange"
      @select="handleSelect"
    />
  </div>
</template>
<script>

import _debounce from 'lodash/debounce';
import { getCollectionSlugs } from 'Api';
import { ALPHANUMERIC_NO_UNDERSCORE_RE, DEBOUNCE_TIME_1K } from 'Config/constants';

const { UiAutocomplete, UiSelect } = window.kiln.utils.components,
  SPACE_REGEX = / /g,
  NONE_OPTION = 'None';

export default {
  components: {
    UiAutocomplete,
    UiSelect
  },
  props: {
    editMode: {
      type: Boolean,
      default: false
    },
    modalMode: {
      type: Boolean,
      default: false
    },
    value: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      autocomplete: [],
      collectionSlugText: '',
      defaultOriginalList: [],
      isActive: false,
      isLoading: false,
      query: ''
    };
  },
  watch: {
    // setting in mounted is not enough, as it could be updated after
    value(newCollectionSlug = '') {
      this.collectionSlugText = newCollectionSlug;
    },
    collectionSlugText(newCollection, oldCollection) {
      // if it's not active, it means is just loading the data
      if (!this.isActive || !this.editMode) return;

      // if field was cleared out without blur, we need to save it only in search
      if (!newCollection && oldCollection) return this.handleSelect();

      this.collectionSlugText = newCollection.replace(ALPHANUMERIC_NO_UNDERSCORE_RE, '');
      this.updateAutocompleteList();
    }
  },
  mounted() {
    this.collectionSlugText = this.value;

    getCollectionSlugs('') // need the empty string or else it will put undefined
      .then((data) => {
        this.defaultOriginalList = this.editMode
          ? [...data.filter(Boolean)]
          : [NONE_OPTION, ...data.filter(Boolean)];

        this.autocomplete = [...this.defaultOriginalList];
        this.isLoading = false;
      })
      .catch(console.error);
  },
  methods: {
    onQueryChange(query) {
      this.isLoading = true;
      this.query = query;

      if (query.length) return this.updateAutocompleteList();

      this.autocomplete = [...this.defaultOriginalList]; // we need to set a default list here
      this.isLoading = false;
    },
    onFocus() {
      this.isActive = true;
    },
    handleSelect() {
      if (!this.editMode) {
        const selectedOption = this.collectionSlugText === NONE_OPTION ? '' : this.collectionSlugText;

        this.$emit('saveCollection', selectedOption);
        this.autocomplete = [...this.defaultOriginalList];
      }
    },
    handleSave() {
      if (this.editMode) {
        // replace space with dash
        this.collectionSlugText = this.collectionSlugText.replace(SPACE_REGEX, '-');
        this.$emit('fieldChange', 'collectionSlug', this.collectionSlugText);
        this.isActive = false;
      }
    },
    /**
     * Updates list of suggestions for autocomplete
     */
    // eslint-disable-next-line func-names
    updateAutocompleteList: _debounce(function () {
      // if it's not active or no text, we should avoid doing unnecessary request
      if ((!this.isActive || !this.collectionSlugText) && this.editMode) return;

      const searchText = this.editMode ? this.collectionSlugText : this.query;

      return getCollectionSlugs(searchText)
        .then((data) => {
          this.autocomplete = [...data.filter(Boolean)]; // Set to avoid dedupes
          this.isLoading = false;
        })
        .catch(console.error);
    }, DEBOUNCE_TIME_1K),
    /**
     * Handle string when in the input changes
     */
    onInputChange() {
      // handle not allowed characters
      this.collectionSlugText = this.collectionSlugText.replace(ALPHANUMERIC_NO_UNDERSCORE_RE, '');
      // refresh autocomplete, this ensures the text and the suggestions are actually updated
      this.autocomplete = this.collectionSlugText
        ? [...new Set(this.autocomplete)]
        : [...this.defaultOriginalList];
    }
  }
};
</script>
<style lang="scss" scoped>
  @import 'Styles/fonts.scss';
  @import 'Styles/helpers.scss';

  .ui-autocomplete {
    /deep/ {
      .ui-autocomplete__clear-button {
        display: none;
      }

      .ui-autocomplete__input {
        font-size: $standard-font-size;
      }
    }

    &.has-floating-label /deep/ .ui-autocomplete__label-text {
      &.is-floating {
        font-size: $small-font-size;
        margin-top: 3px;
      }

      &.is-inline {
        :not(.modal-mode) > & {
          transform: translateY(1.625rem) scale(1);
        }
      }
    }
  }

  // select styles
  .ui-select {
    @extend .select-nowrap-style;

    margin-bottom: 0;

    &.has-floating-label /deep/ .ui-select__label-text {
      &.is-floating {
        font-size: $small-font-size;
        margin-top: 3px;
      }

      &.is-inline {
        transform: translateY(1.625rem) scale(1);
      }
    }

    /deep/ {
      .ui-select__display {
        height: 2rem;
        padding: 0;
      }

      .ui-select__label-text,
      .ui-select-option,
      .ui-select__display-value {
        font-size: $standard-font-size;
      }
    }
  }

  .collection-slug.ui-select /deep/ .ui-select__display {
    line-height: 1.4;
  }
</style>
