<template>
  <div class="formcontrol">
    <label class="formcontrol-label" for="" v-if="optional || label"
      >{{ label }}
      <div class="formcontrol-optional" v-if="optional">Optional</div></label
    >
    <div
      class="select-multiple"
      ref="container"
      :class="{ 'select-multiple--expanded': showAutocomplete }"
      @click="openDropDown"
    >
      <div class="select-multiple-value">
        <input
          ref="input"
          class="select-multiple-input"
          :placeholder="placeholder"
          :size="Math.max(value.length, placeholder.length, 10)"
          v-model="value"
          @keyup="onKeyup"
        />
      </div>
      <div class="dropdown-options" tabindex="0">
        <div
          v-for="(v, i) in displayedAutocomplete"
          :class="{ 'select--active': i == activeIndex }"
          @click="toggle(v, $event)"
          :key="v.id"
        >
          <span v-html="highlight(v.name)"></span>
        </div>
        <div v-if="filtredAutocomplete.length > displayedAutocomplete.length">...</div>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
import AutocompleteOptions from "@/models/AutocompleteOptions";
import { defineComponent, PropType } from "vue";
import toast from "@/utils/Toast";
export default defineComponent({
  props: {
    id: String,
    label: String,
    modelValue: {
      type: String,
    },
    autocompleteList: {
      type: Array as PropType<Array<AutocompleteOptions>>,
      default: () => [],
    },
    placeholder: { type: String, default: () => "" },
    optional: Boolean,
    limit: {
      type: Number,
      default: () => Infinity,
    },
    strictAutocomplete: {
      type: Boolean,
      default: () => false,
    },
  },
  data: function () {
    return {
      value: "",
      activeIndex: -1,
      expanded: false,
    };
  },
  watch: {
    modelValue(v) {
      this.value = this.autocompleteList.find((o) => o.id == v)?.name || "";
    },
    value(value) {
      if (!this.strictAutocomplete) this.$emit("update:modelValue", value);
    },
  },
  computed: {
    filtredAutocomplete(): Array<AutocompleteOptions> {
      const lower = this.value.toLowerCase();
      return this.autocompleteList.filter((o) => o.name.toLowerCase().includes(lower));
    },
    displayedAutocomplete(): Array<AutocompleteOptions> {
      return this.filtredAutocomplete.slice(0, this.limit);
    },
    showAutocomplete(): boolean {
      return this.expanded && this.filtredAutocomplete.length > 0;
    },
    input(): HTMLInputElement {
      return this.$refs["input"] as HTMLInputElement;
    },
  },
  methods: {
    openDropDown: function (e: MouseEvent) {
      this.expanded = true;
      this.input.focus();
      window.addEventListener("click", this.closeDropDown);
      e.stopPropagation();
    },
    closeDropDown: function (e: MouseEvent) {
      if (this.$refs["container"]) {
        if (!(this.$refs["container"] as HTMLElement).contains(e.target as Node)) {
          this.expanded = false;
          window.removeEventListener("click", this.closeDropDown);
          e.stopPropagation();
          if (this.value == "") this.$emit("update:modelValue", this.value);
        }
      }
    },
    toggle(v: AutocompleteOptions, e: MouseEvent) {
      e.stopPropagation();
      this.expanded = false;
      this.value = v.name;
      this.$emit("update:modelValue", v.id);
    },
    onKeyup: function (e: KeyboardEvent): void {
      if (e.key === "Enter") {
        if (this.value === "") {
          this.$emit("update:modelValue", "");
          this.expanded = false;
        } else if (this.activeIndex > -1 && this.activeIndex < this.displayedAutocomplete.length) {
          const v = this.displayedAutocomplete[this.activeIndex];
          this.value = v.name;
          this.$emit("update:modelValue", v.id);
          this.expanded = false;
        } else if (this.strictAutocomplete) {
          toast({
            html: "Vous ne pouvez ajouter que des valeurs prédéfinies",
            classes: "red",
          });
        }
      }
      if (e.key === "ArrowUp") {
        this.activeIndex--;
      }
      if (e.key === "ArrowDown") {
        this.activeIndex++;
      }
      if (this.activeIndex < -1) {
        this.activeIndex = this.displayedAutocomplete.length - 1;
      }
      if (this.activeIndex >= this.displayedAutocomplete.length) {
        this.activeIndex = 0;
      }
    },
    highlight: function (txt: string) {
      if (this.value) {
        const reg = new RegExp(this.value, "ig");
        const highlightedText = txt.match(reg);
        if (highlightedText) {
          const plaintext = txt.split(reg);
          return (
            highlightedText.map((t, i) => plaintext[i] + `<b class="highlight">${t}</b>`).join("") +
            plaintext.pop()
          );
        }
      }
      return txt;
    },
  },
});
</script>

<style src="../assets/css/multiple-select.css"></style>
