<template>
  <div
    v-show="!isHidden"
    class="form-group"
    :class="[
      columnSize,
      {
        'has-icon': faIcon,
        'has-feedback': hasFeedback,
        'has-success': hasSuccess,
        'has-error': hasError,
      },
    ]"
  >
    <label class="control-label" :for="id">
      {{ label }}
      <span class="info">{{ info }}</span>
      <span v-if="isRequired" class="required-marker"></span>
      <span
        v-if="tooltip"
        class="tooltip-info"
        data-toggle="tooltip"
        :title="tooltip"
      ></span>
    </label>
    <div class="dropdown" :class="{ open: showDropDown && showInput }">
      <!-- Selected Item -->
      <!-- <input
        type="text"
        class="hidden"
        :id="id + 'Value'"
        :value="inputValue"
      /> -->
      <button
        v-if="!showInput"
        type="button"
        class="form-control dropdown-toggle"
        :id="id + 'Button'"
        :disabled="!isEnabled"
        @click="onInputFocus()"
      >
        <div v-if="selectedOptionDisplay">{{ selectedOptionDisplay }}</div>
        <div
          v-else-if="searchValue"
          :style="[status === 'failed' ? { color: 'red' } : {}]"
        >
          {{ searchValue }}
        </div>
        <div v-else>
          <i>
            {{ placeholder }}
          </i>
          <span v-if="filteredOptions.length > 0" class="caret"></span>
        </div>
      </button>
      <!-- Default
      <button
        v-else
        type="button"
        class="form-control dropdown-toggle"
        :id="id + 'Button'"
        :disabled="!isEnabled"
        @click="setOnFocus()"
      >
        {{ placeholder }}
        <span class="caret"></span>
      </button> -->
      <!-- Search Input -->
      <input
        v-show="showInput"
        :ref="id"
        type="text"
        class="form-control dropdown-toggle"
        :id="id"
        :placeholder="placeholder"
        :maxLength="max_length"
        :pattern="pattern"
        :required="isRequired"
        @input="onInput"
        @click="onClick"
        @blur="onLeave"
        :value="searchValue"
      />
      <span
        v-show="searchValue"
        @click="resetItem"
        :style="rightActionIconStyle"
        class="fa fa-times-circle"
      ></span>
      <!-- Drop Menu -->
      <div class="dropdown-menu">
        <div class="scrollbars">
          <ul
            v-if="dropdownOptions && Object.keys(dropdownOptions).length > 0"
            class="dropdown-menu"
          >
            <li
              v-for="(v, k) in dropdownOptions"
              :key="k"
              :k="k"
              :v="v"
              @click="onSelect(k, v)"
            >
              <a href="#" :data-value="k" :data-label="v">
                <div v-html="renderOption(v)"></div>
              </a>
            </li>
          </ul>
        </div>
      </div>
      <span
        v-if="iconRender"
        class="form-control-feedback"
        :class="iconRender"
      ></span>
      <div
        v-if="validationText && hasError"
        class="help-block"
        data-validation-error
      >
        {{ validationText }}
      </div>
      <div v-if="errorText" class="help-block" data-validation-error>
        {{ errorText }}
      </div>
      <p v-if="help && !validationText" :id="id + 'Help'" class="help-block">
        {{ help }}
      </p>
    </div>
  </div>
</template>

<script>
import { str2bool, objectToFormatedString } from "../../util";
import axios from "axios";
const TYPING_ICON = "fa-ellipsis-h",
  LOADING_ICON = "fa-circle-o-notch fa-spin",
  FAILED_ICON = "fa-times pointer";

const debounce = (fn, ms = 0) => {
  let timeoutId;
  return function (...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn.apply(this, args), ms);
  };
};

export default {
  name: "bc-search",
  props: {
    option_format: {
      type: String,
      default: "",
    },
    option_display: {
      type: String,
      default: "*",
    },
    search_path: {
      type: String,
      default: "",
    },
    search_method: {
      type: String,
      default: "get",
      validator: (value) => {
        // The value must match one of these strings
        return ["get", "post"].indexOf(value) !== -1;
      },
    },
    search_request_param: {
      type: String,
      default: "search",
    },
    search_start_from_char: {
      type: Number,
      default: 1,
    },
    id: {
      type: String,
      default: null,
    },
    label: {
      type: String,
      default: null,
    },
    value: {
      type: [String, Number, Object],
      default: null,
    },
    options: {
      type: Object,
    },
    placeholder: {
      type: String,
      default: null,
    },
    info: {
      type: String,
      default: null,
    },
    icon: {
      type: String,
      default: null,
    },
    tooltip: {
      type: String,
      default: null,
    },
    help: {
      type: String,
      default: null,
    },
    validation: {
      type: String,
      default: null,
    },
    max_length: {
      type: Number,
      default: null,
    },
    pattern: {
      type: String,
      default: null,
    },
    column_size: {
      type: Number,
      default: null,
    },
    is_enabled: {
      type: [Boolean, String],
      default: true,
    },
    is_hidden: {
      type: [Boolean, String],
      default: false,
    },
    is_required: {
      type: [Boolean, String],
      default: false,
    },
    is_valid: {
      type: [Boolean, String],
      default: null,
    },
  },
  data() {
    return {
      isOnFocus: false,
      isValid: null,
      inputValue: null,
      selectedOption: null,
      showInput: false,
      selectedOptionDisplay: null,
      searchValue: "",
      status: "init",
      dropdownOptions: {},
      filteredOptions: [],
      errorText: "",
    };
  },

  mounted() {
    // if (this.value) {
    //   this.updateValue(this.value);
    // }
    // this.isValid = str2bool(this.is_valid, null);
  },
  updated() {
    // if (this.value) {
    //   this.updateValue(this.value);
    // }
    // this.isValid = str2bool(this.is_valid, null);
  },
  watch: {
    options: {
      immediate: true,
      handler(newOptions) {
        if (newOptions) {
          this.dropdownOptions = newOptions;
        }
      },
    },
    // value: {
    //   immediate: true,
    //   handler(newValue) {
    //     // consol.log("Dropdown: value watch", newValue);
    //     // this.updateValue(newValue);
    //   },
    // },
  },
  created() {
    this.fetchOptionsDebounce = debounce(this.fetchOptions, 1000);
    window.addEventListener("click", this.checkFocus);
  },
  destroyed() {
    window.removeEventListener("click", this.checkFocus);
  },
  computed: {
    isRequired() {
      return str2bool(this.is_required);
    },
    isHidden() {
      return str2bool(this.is_hidden, false);
    },
    isEnabled() {
      return str2bool(this.is_enabled, true);
    },
    hasFeedback() {
      if (this.isValid == null) {
        return false;
      } else {
        return !this.isOnFocus;
      }
    },
    hasError() {
      return !this.isOnFocus && this.isValid === false && this.hasFeedback;
    },
    hasSuccess() {
      return !this.isOnFocus && this.isValid === true && this.hasFeedback;
    },
    columnSize() {
      if (this.column_size) {
        return `col-xs-${this.column_size}`;
      }
      return "";
    },
    faIcon() {
      if (this.icon) {
        return `fa-${this.icon}`;
      }
      return false;
    },
    iconRender() {
      if (this.status === "fetching") {
        return LOADING_ICON;
      } else if (this.status === "failed") {
        return FAILED_ICON;
      } else if (this.status === "typing") {
        return TYPING_ICON;
      }
      return this.faIcon;
    },
    validationText() {
      if (this.validation) {
        if (!this.isOnFocus) {
          return this.validation;
        }
      }
      return false;
    },
    showDropDown() {
      if (
        this.dropdownOptions &&
        Object.keys(this.dropdownOptions).length > 0 &&
        this.isOnFocus
      ) {
        return true;
      }
      return false;
    },
    rightActionIconStyle() {
      let style = {
        "z-index": "100",
        position: "absolute",
        right: "8px",
        top: "0",
        bottom: "0",
        margin: "auto",
        "font-size": "20px",
        cursor: "pointer",
        color: "#ccc",
      };
      if (this.validationText || this.errorText || this.help) {
        style["height"] = "38px";
      } else {
        style["height"] = "18px";
      }
      return style;
    },
  },
  methods: {
    // updateValue(value) {
    //   // console.log("Dropdown update value", value);
    //   this.inputValue = value;
    //   if (value) {
    //     this.$nextTick(() => {
    //       if (this.dropdownOptions && this.inputValue in this.dropdownOptions) {
    //         this.selectedOption = this.dropdownOptions[this.inputValue];
    //       }
    //     });
    //   } else {
    //     // value is empty or null, clear selected option
    //     this.selectedOption = null;
    //   }
    // },
    onInput(event) {
      console.log("on input", event.target.value);
      this.searchValue = event.target.value;
      if (this.searchValue) {
        this.status = "typing";
        if (this.searchValue.length >= this.search_start_from_char) {
          this.fetchOptionsDebounce();
        } else {
          // reset input under the minimum amount of character necessary to start a search
          this.resetItem();
        }
      } else {
        this.resetItem();
      }
      // this.doFiltering();
    },
    onClick() {
      // console.log("on click input");
      this.isOnFocus = true;
      // this.displayUtilityMenu = false;
    },
    onLeave() {
      // console.log("on leave input");
      // this.showInput = false;
    },
    resetItem() {
      this.status = "";
      this.searchValue = "";
      this.selectedOption = "";
      this.selectedOptionKey = "";
      this.selectedOptionDisplay = "";
      this.errorText = "";
      this.dropdownOptions = [];
      this.onInputFocus;
      this.$refs[this.id].focus();
    },
    onSelect(key, value) {
      // console.log("on select input");
      this.inputValue = key;
      this.selectedOption = value;
      this.selectedOptionKey = key;
      this.selectedOptionDisplay = this.renderOption(value, false);
      this.searchValue = this.selectedOptionDisplay;
      this.isOnFocus = false;
      this.$emit("input", { key: key, value: value });
      this.$emit("select", { key: key, value: value });
    },
    onInputFocus() {
      // console.log("on input focus");
      this.showInput = true;
      this.isOnFocus = true;
      this.$nextTick(() => {
        this.$refs[this.id].focus();
      });
    },
    setOnFocus() {
      // console.log("setOnFocus");
      this.isOnFocus = !this.isOnFocus;
    },
    checkFocus(event) {
      // console.log("checkFocus");
      // console.log("element", this.$el);
      // console.log("target", event.target);
      // set onFocus = false if we quit the element
      if (!this.$el.contains(event.target)) {
        // console.log("target not in element");
        this.isOnFocus = false;
      } else {
        // console.log("target in element");
      }
    },
    onOptionRegistered({ key, value }) {
      this.dropdownOptions[key] = value;
    },
    fetchOptions() {
      if (this.search_path) {
        if (this.searchValue) {
          this.status = "fetching";
          let params = {
            [this.search_request_param]: this.searchValue,
          };
          axios({
            method: this.search_method,
            url: this.search_path,
            data: this.search_method === "post" ? params : {},
            params: this.search_method === "get" ? params : {},
          })
            .then((response) => {
              this.status = "";
              this.isOnFocus = true;
              let data = response.data;
              this.dropdownOptions = [];
              this.errorText = "";
              if (data) {
                if (Array.isArray(data) && data.length > 0) {
                  // transform array to indexed object
                  this.dropdownOptions = Object.assign({}, data);
                } else if (
                  typeof data === "object" &&
                  data.constructor === Object &&
                  Object.keys(data).length > 0
                ) {
                  this.dropdownOptions = data;
                } else {
                  this.status = "failed";
                  this.errorText = "No results";
                }
              } else {
                this.status = "failed";
                this.errorText = "No data";
              }
            })
            .catch((reason) => {
              console.log(reason);
              this.status = "failed";
              this.errorText = reason.message;
              this.isValid = false;
            });
        }
      }
    },
    renderOption(option, with_format = true) {
      return objectToFormatedString(
        option,
        this.option_display,
        with_format ? this.option_format : null
      );
    },
  },
};
</script>

