<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="lt('Search')"
      :search-input.sync="searchEntry"
      :filter="customFilter"
      hide-no-data
      clearable
      :no-filter="isTagFilter"
      :append-icon="errorIcon"
      @click:append="handleErrorClick"
      :prepend-icon="allowEdit ? 'fa-edit' : null"
      @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";
/*
States
1) Open form have a preselected Value
init: load preselected value only
change: 
  DROP DOWN need to drop down and have it populate with top 100
  EDIT search as normal but keep preselected value until changed

2) Open form have no value
init: ALWAYS starts with no selection if no value, up to server routes to deal with 0 id selection if they need to

change 
  drop down, get top 100
  edit and search as normal

NO VALUE
  if not valid then there should be a rule enforcing that, not the control's issue

Control always has a value, either it's NO VALUE or it's a selection

DROP DOWN
  if no items already loaded then fetches top 100 IN ADDITION to the preselect if present
  if items already loaded then just shows those items as they are likely from a prior search and user can just search again
  if user clears then drops down it acts as a fresh load of 100 items

PRE-FILL
  NO prefill, fills only on user action or with defaults to save bandwidth.  User must drop down to initiate action or type search text


todo: option to display icon to open the record selected, (we have the type and the id and in v7 you could click on most titles to navigate to that record)
    if I add that then maybe need a "new" option on edit forms because it's a two step way to get to adding a new one of whatever it is without having to go 
    completely out of the page and hunt around lists and shit!!!
    or consider a direct NEW button right there, (this might be a winner)
    or maybe combine the two ideas, if no selection or empty selection then the button acts as new, puts any entered search text into the Name field
    or, if selection then it acts as open
*/
export default {
  created() {
    var vm = this;
    // console.log("CREATED:value is ", this.value);

    //need to add no selection object always, if it's not valid then that's a rule for the form, not the control

    window.$gz.form.addNoSelectionItem(vm.searchResults);

    // debugger;
    //TODO: this may be needed to force new records to have a zero in their no selection valid fields rather than null
    // however it could overwrite a valid value maybe so needs further testing
    //

    //set initial value in control if selected
    if (vm.value != null && vm.value != 0) {
      //It has a prior non empty selection that needs to be fetched
      //note that by default this will just fetch the selected record instead of the prefill list
      // console.log("STUB: created: has value, sb fetched");
      var urlParams = "?ayaType=" + vm.ayaType + "&preId=" + vm.value;
      vm.getList(urlParams);
    }
  },
  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
    },
    allowEdit: {
      type: Boolean,
      default: false
    },
    label: { type: String, default: "" }
  },
  watch: {
    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;
        }
      }

      // console.log(
      //   "watch:searchentry cleared check to see if it's a selected list item, doing search for ",
      //   val
      // );
      // console.log("search results:", vm.searchResults);

      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: {
    lt: function(ltkey) {
      return window.$gz.translation.get(ltkey);
    },
    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-picklist"
      });
    },
    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.$emit("input", e.id);
      }
      this.lastSelection = e;
    },
    replaceLastSelection() {
      // console.log("replace last selection top");
      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) {
            // console.log(
            //   "rpl last selection null but found in list so setting last selection"
            // );
            vm.lastSelection = vm.searchResults[i];
            return;
          }
        }

        // console.log("RPL bailing as last selection is null and not in list");
        return;
      }

      for (var i = 0; i < vm.searchResults.length; i++) {
        if (vm.searchResults[i].id == vm.lastSelection.id) {
          //console.log("replacelastselection bailing, it's in list already");
          return;
        }
      }

      vm.searchResults.push(vm.lastSelection);
      // console.log(
      //   "replacelastselection bottom, search results now:",
      //   vm.searchResults
      // );
    },
    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;
      }
      return item.name.indexOf(queryText) > -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;
      // console.log("getlist: calling api.get.picklist for type ", vm.ayaType);
      //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
      //https://vuejs.org/v2/guide/migration.html#debounce-Param-Attribute-for-v-model-removed
      //-----------------

      var vm = this;

      //NOTE: empty query is perfectly 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.lt("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.lt("ErrorPickListQueryInvalid"));
            return;
          }

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

      //build url
      //vm.fetching = true;

      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>
