<template>
  <div>
    <v-autocomplete
      v-bind:value="value"
      v-on:input="selectionMade($event)"
      return-object
      :items="searchResults"
      :label="label"
      item-text="name"
      item-value="id"
      item-disabled="!active"
      :error-messages="errors"
      :loading="fetching"
      :placeholder="t('Search')"
      :search-input.sync="searchEntry"
      :filter="customFilter"
      hide-no-data
      clearable
      :no-filter="isTagFilter"
      :append-icon="errorIcon"
      @click:append="handleErrorClick"
      :prepend-icon="editIcon()"
      @click:prepend="handleEditClick"
      @mousedown="dropdown"
    >
      <template v-slot:prepend-item v-if="hasError()">
        <div class="pl-2">
          <span class="error--text"> {{ errors[0] }}</span>
        </div>
      </template>
    </v-autocomplete>
  </div>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*  eslint-disable    */
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//NOTE: have to import lodash directly here as no combination was working with the window.$gz._
//it would not recognize window in the function call cache-items
import _ from "../libs/lodash.min.js";

export default {
  created() {
    this.fetchValueIfNotPresent();
  },
  data() {
    return {
      searchResults: [],
      errors: [],
      searchEntry: null,
      lastSelection: null,
      fetching: false,
      isTagFilter: false,
      errorIcon: null,
      initialized: false
    };
  },
  props: {
    value: {
      type: Number,
      default: null
    },
    ayaType: {
      type: Number,
      default: 0
    },
    includeInactive: {
      type: Boolean,
      default: false
    },
    showEditIcon: {
      type: Boolean,
      default: false
    },
    label: { type: String, default: "" }
  },
  watch: {
    value(val) {
      this.fetchValueIfNotPresent();
    },
    searchEntry(val, oldVal) {
      var vm = this;
      //clear any local errors
      vm.clearErrors();
      //if the search entry is in the results list then it's a drop down selection not a typed search so bail
      for (var i = 0; i < vm.searchResults.length; i++) {
        if (vm.searchResults[i].name == val) {
          return;
        }
      }
      if (!val || vm.fetching || !vm.initialized) {
        if (!vm.initialized) {
          vm.$nextTick(() => {
            vm.initialized = true;
          });
        }
        return;
      }
      this.doSearch();
    },
    errors(val) {
      if (this.hasError()) {
        this.errorIcon = "fa-question-circle";
      } else {
        this.errorIcon = null;
      }
    }
  },
  methods: {
    t: function(tKey) {
      return window.$gz.translation.get(tKey);
    },
    hasError: function() {
      return this.errors.length > 0;
    },
    clearErrors: function() {
      this.errors = [];
    },
    handleErrorClick: function() {
      //open help nav for picklist
      window.$gz.eventBus.$emit("menu-click", {
        key: "app:help",
        data: "ay-start-form-select-list"
      });
    },
    editIcon: function() {
      if (!this.showEditIcon) {
        return null;
      }
      if (this.value != 0) {
        return "fa-edit";
      }
      return "fa-plus";
    },
    handleEditClick: function() {
      var idToOpen = 0;
      if (this.lastSelection != null && this.lastSelection.id) {
        idToOpen = this.lastSelection.id;
      }
      window.$gz.eventBus.$emit("openobject", {
        type: this.ayaType,
        id: idToOpen
      });
    },
    selectionMade(e) {
      this.clearErrors();
      if (e == undefined) {
        //this will happen when clear clicked
        return;
      }
      if (e.id != null) {
        //this is required for the control to update and parent form to detect it
        this.$emit("input", e.id);
      }
      this.lastSelection = e;
    },
    fetchValueIfNotPresent() {
      //is there a value that might require fetching?

      var vm = this;
      var val = vm.value;
      if (val == null) {
        return;
      }
      //check if it's in the list of items we have here
      for (var i = 0; i < vm.searchResults.length; i++) {
        if (vm.searchResults[i].id == val) {
          return;
        }
      }
      //is it the no selection item?
      if (val == 0) {
        window.$gz.form.addNoSelectionItem(vm.searchResults);
      } else {
        //Not here, better get it
        var urlParams = "?ayaType=" + vm.ayaType + "&preId=" + vm.value;
        vm.getList(urlParams);
      }
    },
    replaceLastSelection() {
      var vm = this;
      //check if searchResults has last selection, if not then add it back in again
      if (vm.lastSelection == null) {
        //it might be initializing
        for (var i = 0; i < vm.searchResults.length; i++) {
          if (vm.searchResults[i].id == vm.value) {
            vm.lastSelection = vm.searchResults[i];
            return;
          }
        }
        return;
      }

      for (var i = 0; i < vm.searchResults.length; i++) {
        if (vm.searchResults[i].id == vm.lastSelection.id) {
          return; //already there
        }
      }
      //Not there so insert it
      vm.searchResults.push(vm.lastSelection);
    },
    dropdown(e) {
      var vm = this;
      //check if we have only the initial loaded item and no selection item
      if (vm.searchResults.length < 3) {
        //get the default list
        vm.getList();
      }
    },
    customFilter(item, queryText, itemText) {
      //NOTE: I wanted this to work with tags but all it does is highlight all of each row if tag query is present
      //I guess because it later on attempts to do the highlighting and can't find all the entered query
      //it's not clean so I'm just going to make it only highlight if it's a non tag query for now
      //and do no filtering (highlighting) at all if it's a tag query
      if (queryText.includes(" ") || queryText.startsWith("..")) {
        this.isTagFilter = true;
        return false;
      }
      if (this.$store.state.globalSettings.searchCaseSensitiveOnly == true) {
        return item.name.indexOf(queryText) > -1;
      } else {
        //need to do a case insensitive filter and hopefully it mirrors postgres at the backend
        return item.name.toLowerCase().indexOf(queryText.toLowerCase()) > -1;
      }

      //split out just the text search part
      // var searchText = queryText;
      //   if (queryText.includes(" ")) {
      //     //get the non tag part of query if possible
      //     //ignore bad condition of too many terms
      //     var searchTerms = queryText.split(" ");
      //     if (searchTerms[0].includes("..")) {
      //       searchText = searchTerms[1];
      //     } else {
      //       searchText = searchTerms[0];
      //     }
      //   }
    },
    getList: function(urlParams) {
      var vm = this;
      if (vm.fetching) {
        return;
      }
      vm.fetching = true;
      //default params for when called on init
      if (!urlParams) {
        urlParams = "?ayaType=" + vm.ayaType;
        if (vm.includeInactive) {
          urlParams += "&inactive=true";
        }
      }
      window.$gz.api
        .get("PickList/List" + urlParams)
        .then(res => {
          vm.fetching = false;
          if (res.error) {
            throw res.error;
          }
          vm.searchResults = res.data;
          window.$gz.form.addNoSelectionItem(vm.searchResults);
          vm.replaceLastSelection();
        })
        .catch(err => {
          window.$gz.errorHandler.handleFormError(err);
          vm.fetching = false;
        });
    },
    doSearch: _.debounce(function() {
      //NOTE debounce with a watcher is a bit different, currently it has to be done exactly this way, nothing else will work properly
      //https://vuejs.org/v2/guide/migration.html#debounce-Param-Attribute-for-v-model-removed
      //-----------------
      var vm = this;
      //NOTE: empty query is valid; it means get the top 100 ordered by template order
      var emptyQuery = false;
      if (this.searchEntry == null || this.searchEntry == "") {
        emptyQuery = true;
      } else {
        //Pre-process the query to validate and send conditionally
        var val = this.searchEntry;
        //get the discrete search terms and verify there are max two
        var isATwoTermQuery = false;
        var queryTerms = [];
        if (val.includes(" ")) {
          queryTerms = val.split(" ");
          if (queryTerms.length > 2) {
            vm.errors.push(vm.t("ErrorPickListQueryInvalid"));
            return;
          }
          isATwoTermQuery = true;
        } else {
          //one term only so push it into array
          queryTerms.push(val);
          //Marker term, will be weeded back out later
          queryTerms.push("[?]");
        }

        //Now vet the terms
        //Is user in mid entry of a second tag (space only?)
        //will appear as an empty string post split
        if (queryTerms[1] == "") {
          //mid entry of a second term, just return
          return;
        }

        //Is user in mid entry of tag query, just bounce back
        if (
          queryTerms[0] == "." ||
          queryTerms[0] == ".." ||
          queryTerms[1] == "." ||
          queryTerms[1] == ".."
        ) {
          return;
        }

        if (isATwoTermQuery) {
          //check that both terms aren't tags
          if (
            window.$gz._.startsWith(queryTerms[0], "..") &&
            window.$gz._.startsWith(queryTerms[1], "..")
          ) {
            vm.errors.push(vm.t("ErrorPickListQueryInvalid"));
            return;
          }

          //check that both aren't non-tags
          if (
            !window.$gz._.startsWith(queryTerms[0], "..") &&
            !window.$gz._.startsWith(queryTerms[1], "..")
          ) {
            vm.errors.push(vm.t("ErrorPickListQueryInvalid"));
            return;
          }
        }
      }

      //build url
      var urlParams = "?ayaType=" + vm.ayaType;
      if (!emptyQuery) {
        var query = queryTerms[0];
        if (queryTerms[1] != "[?]") {
          query += " " + queryTerms[1];
        }
        urlParams += "&query=" + query;
      }

      if (vm.includeInactive) {
        urlParams += "&inactive=true";
      }
      this.getList(urlParams);
      //------------
    }, 300) //did some checking, 200-300ms seems to be the most common debounce time for ajax search queries
  },
  beforeCreate() {
    //check pre-requisites exist just in case
    if (window.$gz.errorHandler.devMode()) {
      // if (!window.$gz._) {
      //   throw "tag-picker: $gz._ (lodash) is required and missing";
      // }
      if (!window.$gz.translation) {
        throw "tag-picker: $gz.translation is required and missing";
      }
    }
  }
};
</script>
